(no title)
JulianChastain | 1 year ago
def f(x):
if x > 0:
return f(x-1)
return 0
# Here is where a compiler might assume that f(x) is tail recursive, and so do TCE
g = f
def f(x):
return x
g(5)
So according to the python standard, g(5) returns 4, since it calls the original f, but then the first recursive call will go to the new f. If f was TCE'd, then it would return 0, as the actual recursion would be eliminated, so it wouldn't matter that you've reassigned f to a new function.
OskarS|1 year ago
Incidentally: I don't believe that is a violation of lexical scoping. f is scoped globally, inside itself f is not defined, so f(x-1) refers to the globally scoped f. When it's reassigned, you reassign the global f. Nothing here violates lexical scoping, since f is never scoped anywhere other than globally (note that the blog post never claims it is, either)
I don't disagree with Guido's larger point, though, Python probably shouldn't use TCO. The debugging/stack trace point is very true, and also it's just not Pythonic to write algorithms TCO style. You just don't need to, in Python.
wk_end|1 year ago
He goes on, later in the post, to describe how he’d go about adding tail calls - although this treatment is also confused.
JulianChastain|1 year ago
And your understanding of why python doesn't permit TCE is because functions are globally scoped with indefinite extent?
Jtsummers|1 year ago
This would work for every instance of call-return pairs except in try statements and similar (anything that that has whatever Python calls unwind-protect). Since, in those cases, the except/finally/else of a try is code that may be executed (or is always executed in the case of the finally) after the call but before the return.
So it really does come down to a desire to prevent the use of deep call stacks (auto-recursion is just one case that would have been optimized here) rather than a true technical limitation. This could even have been brought in incrementally over the years and provided as an option.
bhickey|1 year ago
When would someone want to do this?
JulianChastain|1 year ago
For example:
fooval will then be equal to whatever value foo printed to the console, otherwise foo will behave exactly the same as normal (assuming it only printed a single value), and print will even behave normally afterwards