On 20 January 2014 10:13, Terry Reedy firstname.lastname@example.org wrote:
Proposal (mostly not mine): add 'return from f(args)', in analogy with 'yield from iterator', to return a value to the caller from an execution frame running f(args) (and either reuse or delete the frame that ran 'return from'). The function name 'f' would not have to match the name of the function being compiled, this would actually be TCO, even if it were nearly always used for recursive tail calls. That does mean that is would work for mutually tail recursive functions.
As someone who is happy with the status quo, "return from" seems to me to be the only sensible way to incorporate it into the language. Direct analogy with yield from, clear semantics ... I like it.
Any PEP should admit that the feature might be abused. Someone might write
return from len(composite) Unless return from refuses to delete the frame making a call to a C function, the effect would be to save a trivial O(1) space as the cost of deleting the most important line of a stack trace should len() raise. But I think this falls under the 'consenting adults' principle. A proposed doc should make it clear that the intended use is to make deeply recursive or mutually recursive functions run and not to replace all tail calls.
Consenting adults does make things nice and simple.
I'm not proposing the following semantics, but I can think of an alternative that might be useful, but likely difficult (and costly) to implement, and difficult to explain. When code goes through a "return from", that frame is retained, but when a new frame for the same code object is created in the call stack, you *then* delete the calling frame.
Hmm - actually, you could keep a structure (e.g. a dict) on the side mapping code objects to the most recent frame for that code object - that would make it reasonably cheap to do. Wouldn't get particularly large either since you'd only be recording frames that continued through a "return from".