10 ms·
A function decorator that rewrites the bytecode to enable goto in Python
- paiute 5y agoyes! goto is one of the 2 things python got wrong. The other is the ability to deliver end user executables.
- mikepurvis 5y agoDon't know if I agree about the goto thing, but there are actually a number of options now for delivering varying degrees of self-contained Python executable. 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. [1]: https://github.com/pantsbuild/pex https://github.com/pantsbuild/pex
- paiute 5y agoI've been using nuitka. but really it should be part of the language by now.
- jitl 5y agoThere are a ton of options in Python but none are satisfying compared to eg Golang.
- mikepurvis 5y agoOh sure, a statically-compiled language is always going to win on this for just having it out of the box. 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.
- lmm 5y agoThis sounds like a case of perfect being the enemy of good. Yes, no deployment system will cover all cases. But that doesn't mean it's impossible to make a system that's good for most cases.
- ladberg 5y agoReally? I can't think of why I would want to use a goto in Python, and if I did it would definitely make it not "Pythonic". 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)
- stOneskull 5y agoi can only think of where you want to break out of all nests rather than just the current one.. i still wouldn't use it though.
- echelon 5y ago> Python is 30 years old, is there any popular language created in the last 30 years that has goto? Julia (9 years old) https://sodocumentation.net/julia-lang/topic/5564/-goto-and--label https://sodocumentation.net/julia-lang/topic/5564/-goto-and-... Golang (11 years old) https://golang.org/ref/spec#Goto_statements https://golang.org/ref/spec#Goto_statements Lua (28 years old) http://lua-users.org/wiki/GotoStatement http://lua-users.org/wiki/GotoStatement
- ladberg 5y agoWow I'm actually pretty blown away! I use Go on a daily basis and have never seen it used anywhere or had any clue it was in the language. 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".
- umanwizard 5y agoWhy does it go against the Go ethos? (Asking out of curiosity. I’ve never used the language.)
- ladberg 5y agoI feel like they usually prioritize simplicity and readability instead of tricks, syntactic sugar, and one-liners. 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 ?.
- ufo 5y agoOne thing I don't like about goto is that it allows the creation of irreducible control flow. Makes all kinds of optimizations and program analysis more difficult. When I have the chance, I advocate for more well behaved alternatives such as labeled break statements. Although they're more restrictive, most of the time they're all you need.
- paiute 5y agoyes they can be used for evil but how are exceptions different?
- klyrs 5y agoThis is true, but I suspect that you're getting downvoted because python doesn't do bytecode optimization.
- nerdponx 5y agoCPython doesn't. But the other Python implementations (PyPy, GraalVM, et al) don't even use the CPython bytecode.
- klyrs 5y agoAlso true... but this decorator isn't going to work in that context.
- masklinn 5y agoCpython absolutely does, just not much of it (it has a peephole optimiser with a very small set of opts).
- eru 5y agoProperly implemented tail calls are all you need. You can get loops and goto etc from there. (You might still want extra first class support for eg exceptions.)
- dehrmann 5y agoJava actually has an elegant-for-Java feature that removes most credible uses of goto. You can label and break out of standalone code blocks. It makes error handling without exceptions no bad. label: { break label; }
- abnercoimbre 5y agoOh my goodness! I'm using this right away (yesterday I was lamenting lack of goto for this exact use case.) This is just Java, right? I don't think I've seen this in the C/C++ specs or compiler extensions.
- superdisk 5y agoWell if you're using C, you could just use a proper goto.
- jcranmer 5y agoLabeled break/continue are present in most languages that postdate Java. Go, JavaScript, Kotlin, Nim, Rust, Zig, for example, all have labeled break/continue as well. The only notable post-Java language I'm aware of that doesn't have it is C#. Languages that predate Java generally don't have such a feature--and this includes C/C++.
- aurelianito 5y agoYou can have the same flow in python raising and catching an exception.
- nerdponx 5y agoDoesn't Perl also have this? It would be a great feature in Python, although I wouldn't use it very often.
- gnubison 5y agoIn Perl, any “bare block” is equivalent to a loop that only runs once. Useful in conjunction with redo too.
- loeg 5y agoSurely the ten+ year Python 3-is-incompatible-with-2 saga was also a mistake.
- eru 5y agoThey could have tried to handle this in a better way, but some incompatible changes were useful and probably necessary. 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?
- masklinn 5y agoWouldn’t have been very useful, there were not that many incompatible syntactic changes you could not ignore or paper over (string literals were the main issue until u”” was restored) and it would not have helped any with the semantic & api changes.
- BiteCode_dev 5y agoPython added a GOTO a few years ago, by mistake, with asyncio.ensure_future(): https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ https://vorpus.org/blog/notes-on-structured-concurrency-or-g... 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.
- JNRowe 5y agoThere was an equally intriguing Python goto implementation posted last year¹, with some interesting comments²(including some in the gist itself). This version does seem better, but I'm not really sure that is a good thing. ¹ https://gist.github.com/georgexsh/ede5163a294ced53c3e2369ccaa392cc https://gist.github.com/georgexsh/ede5163a294ced53c3e2369cca... ² https://news.ycombinator.com/item?id=23076859 https://news.ycombinator.com/item?id=23076859
- ufo 5y agoJesus, what a disgustingly clever hack! I wonder if we could use a similar mechanism to finally add a "continue" to Lua.
- klyrs 5y agoIt's truly a thing of beauty. I can't wait to test what happens when you put labels or gotos in expressions...
- tedunangst 5y agoYeah, you can patch calls to continue() to instead be jumps.
- daurnimator 5y agoLua has `goto` since 5.2; you don't need a continue keyword. e.g. 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
- ufo 5y agoI know we can do that, but I still want continue ;)
- OJFord 5y agoThat's nicer than continue really (as someone who doesn't know and has never written Lua) - works for whichever level of nested loops like that that you want, and allows/somewhat forces you to come up with a name that might be clearer what it's for.
- jstanley 5y agoIn Perl, "next" can take a label: LOOP: while (foo()) { while (bar()) { if (baz()) { next LOOP; } } }
- btown 5y agoAlong the lines of rewriting bytecode at runtime, https://www.python.org/dev/peps/pep-0302/ https://www.python.org/dev/peps/pep-0302/ lets you arbitrarily hook Python's import process and rewrite .pyc files as desired. 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-new-assertion.html http://pybites.blogspot.com/2011/07/behind-scenes-of-pytests... (https://docs.pytest.org/en/6.2.x/assert.html 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!
- pjmlp 5y agoBack in 1999 we used similar arcane techniques to ship encrypted Tcl scripts.
- AshamedCaptain 5y agoAnd probably still do the same today...
- borzunov 5y agoI do the same in my module that enables increment operators in Python by patching the bytecode for two unary plus/minus ops: https://github.com/borzunov/plusplus https://github.com/borzunov/plusplus
- noduerme 5y agoJust... out of curiosity as someone who learned to code in BASIC on a TRS-80... WHY ON EARTH would you ever want goto or gosub statements instead of proper loops and methods? It's not like they're faster. They certainly don't make code more readable. The last time I had to use that type of construct was gotoAndStop() in Flash, which at least had the benefit of queueing up a bunch of art and sound effects. Other than the "neat-o" factor, what's the use case or impetus behind this apparent horror?
- simion314 5y agoI had to use GOTO label, once so far, as a way to quickly exit from inside nested loops - you can do it without GOTO but the point was to be efficient(like if you work with the pixel colors of a big image , each extra instruction inside the loops will have a visible time effect).
- zweice 5y agoIs that faster than (or comparable to) raising an Error in the inner loop and catching it outside the outer loop?
- loa_in_ 5y agoInternal error bubbling code is slow and can change from release to release. And it's definitely not intended for the job.
- simion314 5y agoprobably faster since it was built for this purpose, throwing an error would have to at least create an exception object, then create stack trace and the other setup stuff. 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.
- noduerme 5y agoIn a situation like that I would usually define a boolean before entering the top loop, and set that true within once a condition is met, causing all the outer loops to break if that condition is true. I can't imagine there would be a major speed difference in some other way of breaking all the loops to jump to a different line of code.
- est 5y agoJavascript has a rare yet similar feature called label https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- hamilyon2 5y agoExceptions are forward gotos. A "while" loop with continue and break is backward goto. The only thing missing is break from nested while. Java has one, called break with label, one of more obscure features of language. So, in a sense, python already does have goto.
- cute_boi 5y agoSo rust also has goto :)
- Spivak 5y agoAll control flow constructs in modern programming languages are about codifying the safe uses of goto and setjmp. For example defer and friends are goto cleanup; and yield and exceptions are setjmp.
- brundolf 5y agoSometimes a feature of a programming language is about making it really inconvenient to do something you shouldn't be doing
- anonymoushn 5y agoGreat! It's too bad that python's jump instructions only accept constant targets or constant offests (which seem like they end up being equivalent), otherwise this approach could also support labels-as-values.