I wonder why supporting TCO or not has anything to do with the language. I mean isnt it up to the compiler or interpreter? If a compiler can get the same final results with TCO, then why shouldn't it? And the definition of a language should not define how a compiler works internally only what the actual effect of the language instructions should be. Compiler writers should be free to do what they want to realize the defined effect.
BTW as someone that moved from Pascal to C and C++, I can appreciate the ugliness of a lot of C shorthand syntax. It is confusing and can cause a lot of bizarre and hard to catch bugs.
As Guido says, TCO is not an optimzation, it's a language feature. Here's his reason, which I think is pretty sound:
"Second, the idea that TRE is merely an optimization, which each Python implementation can choose to implement or not, is wrong. Once tail recursion elimination exists, developers will start writing code that depends on it, and their code won't run on implementations that don't provide it: a typical Python implementation allows 1000 recursions, which is plenty for non-recursively written code and for code that recurses to traverse, for example, a typical parse tree, but not enough for a recursively written loop over a large list." - http://neopythonic.blogspot.com/2009/04/tail-recursion-elimi...
The problem with TCO is that it makes it impossible to get accurate stack traces for a function. If you optimize away the stack frame, there's no way to tell the user "this is what was running when the error occurred." You get odd behavior where a function may appear to call another function which never appears in its program text, because the intervening stack frame has been optimized away.
Stack traces are part of the Python language (besides looking pretty, the traceback module lets you inspect them), so it'd be really hard for a conforming implementation to include TCO - at least the type that actually has tail recursion run in constant space.
Java faces a similar problem with HotSpot's inlining, which is why you occasionally get <compiled code> in a Java stack trace instead a line and file number. They seem to have some hack in to avoid eliding the stack frame entirely though. This is probably what I'd do if I were designing language: push a bare-bones stack frame with just the debug info, but pop all the unused temporary working storage. Or punt on general TCO and just optimize tail-recursion - isn't that what Python was proposing to do with the @tailcall decorator anyway?
The languages I know of with TCO - gcc and Scheme - have really terrible debugging support. IMNSHO, I think that giving up debugging info for TCO is a poor tradeoff.
BTW as someone that moved from Pascal to C and C++, I can appreciate the ugliness of a lot of C shorthand syntax. It is confusing and can cause a lot of bizarre and hard to catch bugs.