It should only be called Tail Call Elimination.
A lambda can be as big of an expression as you want, including spanning multiple lines; it can't (because it is an expression) include statements, which is only different than lambdas in most functional languages in that Python actually has statements.
Looking at python from the outside a lot of changes since GvR stepped down seem like stuff he'd not have been fond of.
The answer is no, it will not. Instead they'll just keep adding more and more syntax. And more and more ways to do the same old things. And they'll say that if you want "fast" then write a native module that we can import and use.
So then what's the point? Is Python really just a glue language like all the rest?
https://www.youtube.com/watchv=qCGofLIzX6g
One case study Ronacher gets into is the torturous path taken through the Python interpreter (runtime?) when you evaluate `__add__`. Fascinating stuff.
If your only metric for a language is speed then nothing really beats hand crafted assembly. All this memory safety at runtime is just overhead. If you also consider language ergonomics, Python suddenly is not a bad choice at all.
Only if you know the micro-architecture of the processor you are running on at great depth and can schedule the instructions accordingly. Modern compilers and vms can do crazy stuff at this level.
> Python is fast enough for a whole set of problems AND it is a pretty, easy to read and write language.
It is definitely easy to read. But speed is debatable. It is slow enough for my workload to start wondering about moving to pypy.
While Eve Online isn’t an FPS, it is an MMORPG written in stackless Python, and seems to be doing OK.
Python's problem is that the non-new stuff is not always backwards compatible. It happens way too often that A new python version comes out and half the python programs on my system just stop working.
Also, free-threading is coming so we'll have threads soon.
I don't know if Python can every really be fast as by design, objects are scattered all over memoryand even things like iterating a list, you're chasing pointers to PyObject all over the place - it's just not cache friendly.
EDIT: yes and there’s pypy as well as pointed out below. Basically you gotta use an alternative python implementation of some kind.
It seems like it solves the same problem (saving the function call overhead) and has the same downsides (requires non-standard compiler extensions)
EDIT: it seems the answer is that compilers do not play well with direct-threaded interpreters and they are able to perform more/better optimizations when looking at normal-sized functions rather than massive blocks
(More here: https://noelwelsh.com/posts/understanding-vm-dispatch/)
> they are able to perform more/better optimizations when looking at normal-sized functions rather than massive blocks
It's not the size of the function that is the primary problem, it is the fully connected control flow that gums everything up. The register allocator is trying to dynamically allocate registers through each opcode's implementation, but it also has to connect the end of every opcode with the beginning of every opcode, from a register allocation perspective.
The compiler doesn't understand that every opcode has basically the same set of "hot" variables, which means we benefit from keeping those hot variables in a fixed set of registers basically all of the time.
With tail calls, we can communicate a fixed register allocation to the compiler through the use of function arguments, which are always passed in registers. When we pass this hot data in function arguments, we force the compiler to respect this fixed register allocation, at least at the beginning and the end of each opcode. Given that constraint, the compiler will usually do a pretty good job of maintaining that register allocation through the entire function.
It's not a downside if:
(a) you have those non-standard compiler extensions in the platforms you target
(c) for the rest, you can ifdef an alternative that doesn't require them
Do check out the articles in the top most comment.. about how tail call optimization gets you faster interpreters.
It completely eliminates the overhead of function calls in the generated machine code while you still your code modularly using functions.
I published this technique four years ago, and it's very exciting to see that others have taken up the cause and done the work to land it in CPython.
I had a similiar idea that Python could have `return from f()` to support tail calls without the issues raised about implicit tail calls
https://blog.reverberate.org/2021/04/21/musttail-efficient-i...