Language Design Is Not Just Solving Puzzles is a rather interesting article by Guido van Rossum about the impossibility of an elegant syntax for multi-line lambdas in Python. Worth reading, and in large parts I agree with him. However, I then stumble over such a last paragraph:

And there's the rub: there's no way to make a Rube Goldberg language feature appear simple. Features of a programming language, whether syntactic or semantic, are all part of the language's user interface. And a user interface can handle only so much complexity or it becomes unusable. This is also the reason why Python will never have continuations, and even why I'm uninterested in optimizing tail recursion. But that's for another installment.

I am quite willing to accept that continuations are complex - but not because of the interface. For the interface for continuations, you only need the callcc call to bind the continuation and a simple function syntax to trigger the continuation. The main problem with continuations lies in the cooperation with generators and exceptions - what happens when a continuation is triggered within a generator? What happens when an exception is triggered within a continuation? These are the difficult aspects - which, by the way, also make Scheme implementers sweat, which is why exceptions are not particularly popular there (the same problem, just viewed from the other direction).

So okay, no continuations in Python - even though we already have poor-man's continuations with pickable generators (or with greenlets, or with cloneable coroutines, or one of the many other approaches to obtain subsets of continuation features).

But what on earth is complex about tail-call optimization (because it's not just about tail recursion)? It is so primitive that it can be implemented transparently for the programmer - if a tail call is present, do not note a return address on the stack, but reload the parameters in the stack frame and note a simple jump. If you want to be nice, you can introduce a pseudo-function "tailcall" that throws an exception if it is not to be executed in a tail call position. There may be further conditions under which tail calls cannot be optimized - but these can also be incorporated into a corresponding check.

It is precisely the function overhead that makes some algorithms only awkwardly implementable in scripting languages. And tail-call optimization would definitely help here. Especially in situations where you have a chain of small function calls. As far as I'm concerned, it can also be an optimization that is only activated at -O (or -O2 or something else).