Equality of Recursive Structures [Was: Closure Compiler in 3.9
?]
Colin Putney
cputney at wiresong.ca
Sat May 12 18:18:31 UTC 2007
On May 12, 2007, at 7:38 AM, Tony Garnock-Jones wrote:
>> One more example, that is even more striking and that doesn't use
>> nasty reflection tricks. Imagine that #add:with: was called from a
>> subclass implementation using super. Recycling the stack would
>> clearly
>> change the behavior of the code:
>
> How? The stack frame, at the point the super send has just been made,
> has exactly one role remaining: to return to its caller. Nothing can
> happen between the stack frame becoming active again and its immediate
> return to its calling frame.
The basic problem that Lukas was pointing out is that tailcall
elimination bypasses message dispatch on the recursive message, which
can potentially violate the semantics of Smalltalk. In Lukas' example
above, the "tail call" actually resolves to a different method, so
it's not a tail call at all. Whether a method is tail-recursive
depends on how it was called in the first place, and what code
executes between when it's invoked and when it recurses.
Now, you might say that none of that makes it impossible to do tail-
call elimination, you just have to work hard to avoid getting caught.
The VM could perform the dispatch and only reuse the stack frame if
the message resolves to the same method. Ok, this is true. But tail-
call elimination is Smalltalk isn't the clear win that it is in, say,
Scheme.
Consider: It has to be done by the VM during execution, with a
(small) performance cost in the case where there is no tail
recursion. The tail call is no longer a simple goto, because the VM
still has to do the message dispatch. The VM also has to trap
references to thisContext to avoid getting caught that way. And
finally, Smalltalk does a lot less tail recursion than functional
languages, if only because our collections are based on Array rather
than Association.
Colin
More information about the Squeak-dev
mailing list
|