A function decorator that rewrites the bytecode to enable goto in Python
github.com
github.com
As a practical application, pytest uses this to take the statement `assert foo == bar` and rewrite the AST into a number of instructions that extract the values of foo and bar and print them if the assertion fails: http://pybites.blogspot.com/2011/07/behind-scenes-of-pytests... (https://docs.pytest.org/en/6.2.x/assert.html for those unfamiliar with the library) - so if you use pytest, you're already relying on these arcane techniques!
I wonder if we could use a similar mechanism to finally add a "continue" to Lua.
for z=1,10 do
for y=1,10 do
for x=1,10 do
if x^2 + y^2 == z^2 then
print('found a Pythagorean triple:', x, y, z)
print('now trying next z...')
goto zcontinue
end
end
end
::zcontinue::
end LOOP:
while (foo()) {
while (bar()) {
if (baz()) { next LOOP; }
}
}This version does seem better, but I'm not really sure that is a good thing.
¹ https://gist.github.com/georgexsh/ede5163a294ced53c3e2369cca...
label: {
break label;
} 'label: loop {
break 'label;
}
And if you want to go one further on that, you can break with value because Rust is expression-oriented: fn main() {
println!("Hello, {}!", 'label: loop {
break 'label "world";
});
}https://docs.swift.org/swift-book/ReferenceManual/Statements...
(And I always forget about it)
This is just Java, right? I don't think I've seen this in the C/C++ specs or compiler extensions.
You can get loops and goto etc from there.
(You might still want extra first class support for eg exceptions.)
We are still paying this mistake as of today: most devs don't scope their async tasks lifecyle leading to a huge spaghetti code.
GOTOs are too easy to misuse.
We used to have only GOTOs, no loop, no if... But specialized keyword are better: they enforce a cleaner code, leverage conventions, play batter with tooling and make the whole experience easier to read and debug.
Python is 30 years old, is there any popular language created in the last 30 years that has goto?
(And also I emphatically agree on the end user executable thing)
For example lines 15 through 20 ended up like this:
D15 = 40000
D16 = min(D1, D15)
D17 = min(D14, D16)
D18 = max(D1-D10, 0)
D19 = min(d1, 163300)
D20 = min(D15, D19)
The variable numbers match the form's line numbers, and the code is a straightforward implementation of the instructions for the line.The instructions include things like "If line X is greater than line Y, go to line Z".
I think the code would have been clearer if I could have used goto to match the instructions instead of having to convert to if blocks. For the forms I was interested in at least the if blocks were all fairly simple and the lines in the code were all in the same order as the lines on the form, but I'm not sure that would be true for all of the IRS forms.
And bonus, you can put them in several files, and import them when your program grows. Which means you can then call them in the shell to play with them.
It will make the whole experience much easier.
And for the tax stuff, you wouldn't even need to worry too much about having properly optimized tail calls, as the business logic here is unlikely to blow up your stack.
The code’s logic would be able to better match the logic flow of the tax statement logic flow which often say things like “if no whatever, skip to #farther.down.the.page.”
Sometimes it’s best to let art^h^h^hcode imitate life.
Julia (9 years old) https://sodocumentation.net/julia-lang/topic/5564/-goto-and-...
Golang (11 years old) https://golang.org/ref/spec#Goto_statements
Lua (28 years old) http://lua-users.org/wiki/GotoStatement
PHP perhaps gets honorable mention for not originally having a goto statement, but adding one something like 10 years later.
Zig moved in the opposite direction. It had one at first, and then removed it: https://github.com/ziglang/zig/issues/630
To jump backwards, there's labeled continue. To jump forwards, there's labeled break. The use case that computed goto tries to solve is addressed with labeled continue on a switch [1]
Restricted versions each covering a major use case are easier to reason about, and to optimize.
Anyhow, pretty much every version of “goto” using the name implemented or proposed for Python or other structured languages is castrated: typically, it take only a static label and has restrictions on where it can jump based on structure (out of blocks but not into blocks, within the same function, is pretty typical.)
Proper goto can jump anywhere in the program, even dynamically computed at runtime, and if state isn't set up the way the code jumped to expects, too bad. Everything more restricted is just dickering about how much it should be castrated.
These features already have reasons to exist, because they solve control flow scenarios. So there they are. And then we are brought the question of introducing goto, and there's just nothing that it adds. It would make the language more complicated for no reason.
With goto you can't know at a glance if the code is following those patterns or doing some kind of spaghetti nonsense. It hurts readability.
If you had asked me a few minutes ago if Go had goto I would have said "definitely not and they would never add it because it goes against the Go ethos".
For example there's no ternary operator. Instead you'll have to write out a few lines of if/else. There's no function overloading or operator overloading, no built in min/max, and currently no generics (though they're being added).
They definitely try to keep the number of keywords down to a minimum compared to languages like Swift where you could write the same business logic in fewer lines using stuff like try, guard, !, and ?.
Perhaps files could have declared at the top whether they were Python 2 or 3, and the pyc could have been kept as compatible as possible?
When I evaluated the landscape a few years ago, I settled on PEX [1] as the solution that happened to fit my use-case the best— it uses a system-provided Python + stdlib, but otherwise brings everything (including compiled modules) with it in a self-extracting executable. Other popular options include pyinstaller and cx_freeze, which have different tradeoffs as far as size, speed, convenience, etc.
But that can also be seductive in its own way, like when you get used to just deploying a single binary but then suddenly have an application that also includes data files— do you do the go:embed thing to maintain the glorious single binary, or do the pieces go in an archive together? If it's that one, do you find the data at runtime with a flag, or an envvar, or a relative path, or something else?
Undoubtedly, Go is easier than Python or Ruby, especially for the trivial case. But deployment is overall a non-trivial problem.
For gosub, what's the issue? It is a method call.
As i said I code for almost 20 years and I only had to use it once so far, but people that maybe work a lot more with stuff that needs a lot of performance might use it much more often.
In case you haven't heard the term, structured programming is the term that was used for replacing goto with a handful of commonly used control flow structures. A loop, a function with a return statement, and some kind of case statement (or multi branch if) were the basic ones.
If you look at modern languages today almost all of them have the same set of control flow constructs. They have an if statement, a loop, some kind of function with a return statement, most have some kind of case or multi-branch if, and must have some sort of exceptions. (If was present before structured programming; exceptions were added later.)
If you look at the very oldest programming languages they may have some of these control flow structures but they definitely have two: the if statement and the goto. Because the goto statement is strictly more powerful than these other control structures. If you have a language that doesn't support exceptions but does have a goto, then you can write an exception-like flow using goto. If you have a language that doesn't have break or continue for its loops you can build a loop that works that way using goto. If you're programming language doesn't have the broken form of case statement (that falls through to the next branch) so you can't build Duff's device [https://en.m.wikipedia.org/wiki/Duff%27s_device], then you can build that using goto.
In fact, the combination of if and goto is powerful enough to create any possible (single threaded) flow control structure including ones you and I have never even thought of.
The reason that structured programming was such an important and powerful step forward is because it made the language strictly less powerful. Because the language was less powerful, it was possible to reason more clearly about what the code could or couldn't do. In particular, it allowed a programmer to make certain assumptions about locality. If you started reading at the top of a function and worked your way down you could reason about what this function did in isolation: perhaps the tangle of loops and ifs and try-except blocks in the function are confusing, but at least you don't have to read the entire rest of the program to be certain what it is doing. With goto in your language that guarantee is gone: you might have to understand the entire rest of the program in order to figure out any one function.
So, we gave up the power to create certain flow control constructs in order to make it possible to reason about our languages. But there is nothing that says that the evolution of programming languages is finished. Exceptions are pretty nifty, and they were not part of the original toolkit. Maybe there is another control flow structure out there waiting to be discovered which is extremely useful for solving certain kinds of problems. Someone with goto in their language could discover and use that control flow structure, while those of us without goto cannot.
The same is true, to a greater degree, for function calls.
In eg. C goto:s are function scope.
Is much more elegant than a loop, or at least easier to read since you only need to really pay attention to the happy path.
if failed: do_thing()
This is covered in the Julia docs, where they argue recursion is more readable than goto
https://sodocumentation.net/julia-lang/topic/5564/-goto-and-...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
For example defer and friends are goto cleanup; and yield and exceptions are setjmp.