[self-interest] Reason for closure/method discrepancy?
Jecel Assumpcao Jr
jecel at merlintec.com
Wed Dec 19 19:29:54 UTC 2001
> Can anyone justify closure treatment in self? It would seem to be
> more in the spirit of self to merge closures with methods and perform
> a purely dynamic message lookup, that is search block
> locals/parameters, then follow parent slots (outer closures - and now
> deprecated 'methods').
At the language definition level (the implementation is an entirely
different story) things are pretty close to what you proposed. But
methods are considered prototypes which must be cloned in order to get
At least in theory, a prototype and its clone would be considered the
same type or class of object. So it would be correct to say that
methods and closures are already merged.
To see why method invocation must generate a clone, just imagine a
recursive method or one used in several parallel threads. The different
execution contexts would want to store different values in the argument
slots and local slots, so we can't get by with just one.
> This would have an interesting side effect of
> erasing the difference between closures, methods and objects - any of
> these could be stuck into a slot and sent at least a 'value' message.
Would fetching something from a slot automatically involve sending
'value' to what was found there? If so, blocks would no longer work
properly (more below). If not, methods would no longer work properly.
> A method implementation would become therefore just another object
> (with local, parameter and parent slots) which is sent a 'value'
> message by default, but can accept other messages!
A closure (context object, activation, whatever name you want) can
already accept many messages, though the current implementation doesn't
deal with method slots inside methods.
> Then it is up to the programmer to decide whether to write
> a 'block' inside a 'method' (an anonymous closure), create a method
> (a named closure) or send messages to object or methods (that are
> also objects) interchangeably.
Blocks turn out to be much more complicated than they appear at first.
In fact, we need three separate objects to support them:
block literal: this bundles up all the information in source and
gets stored in the method object
block context: this is the name I gave this in my tinySelf
interpreter, but it really isn't a context object at all. It must point
to the block literal for later use, point to the currently executing
context for later use, and have 'traits block' as a parent so we can
send all kinds of interesting messages to it ('value' is the most
important, but we need 'whileTrue:', 'millisecondsToRun' and many
block method context: this is created as the result of sending
'value' to the block context. It is cloned from the method found in the
block literal but its parent slot is set to point to the context saved
in the block context instead of the receiver like for normal methods.
This way we have a chain of closures like you wanted.
For a single block literal we might create several block contexts since
the method in which it appears might be invoked multiple times. For a
single block context we might create seveal block method contexts since
it might receive several 'value' messages.
> As for the non-local return out of closures, is there a really good
> reason for it? Why not return to the outer scope (other than perhaps
> a clumsier syntax)?
Unless you have a "^" before the last expression in a block, it does
return to the outer scope.
[ 1 + 2. 3 + 4 ] value
But that is not always what you want. Sometimes you need to "unwind" a
deeply nested computation:
arg < 0 ifTrue: [ ^ 1 ].
This lets us relax the rules of strict structured programming.
Otherwise we would have to do:
arg < 0 ifTrue: [ 1 ]
For many real programs, being unable to escape inner scopes in an
unstructured way can become quite painful (see Pascal vs C).
> Forgive my possible stupidity - I am stuck in x86 world and haven't
> been able to explore self personally. I am amazed at the clarity of
> reasoning behind self, with this minor exception. Perhaps someone
> can clarify this.
These are very good questions and I hope I understood them correctly
and was able to explain some of the issues involved. I have been trying
to simplify blocks or unify them with methods since my 1984 Smalltalk
design (http://www.lsi.usp.br/~jecel/st84.txt) and would very much like
to see a simpler solution for Self.
More information about the Self-interest