[squeak-dev] A question about block closures.

David Goehrig dave at nexttolast.com
Wed Jul 8 11:53:19 UTC 2009


On Wed, Jul 8, 2009 at 2:04 AM, Eliot Miranda <eliot.miranda at gmail.com>wrote:
>
>
>> You could do something analogous with messages and methods an d have the
> Vm associate the receiver with the activation in... a message send :)
> If you had a dictionary that cached translations form short forms of
> selectors, e.g. myJSFunc:with: -> myJSFunc:with:with: then your code might
> look something like
>
> doesNotUnderstand: aMessage
> "Generic catch all that performs all selectors"
> (self can: aMessage selector) ifTrue:
>  [actualSelector := self s: aMessage selector.
>  ^self perform: actualSelector
>  withArguments: (aMessage arguments, (Array new: actualSelector numArgs -
> aMessage selector numArgs))]
>
> Would this be better?
>

Well it it had a prayer of working :)  Here's a little backstory.  The way
this object works is it inherits from IdentityDictionary has two accessor
methods:
has: aProperty of: aValue
        " This corresponds to object.property = value and object['property']
= value"
        self at: aProperty put: aValue.
        ^ self.

and

s: aProperty
       " This corresponds to object.property and object['property']"
       ^ self at: aProperty ifAbsent: [^ nil ].

For a very limited sets of methods such as these, the ones that can not be
overridden by end user code, these fields are accessed by doing a message
send to the object, and the dNU routine determines which route to return
based on the method can:

can: aSymbol
     " This corresponds to the javascript:  Object.prototype.can =
function(k) { return this.hasOwnProperty(k) && typeof(this[k]) == 'function'
}"
     ^ ( self s: aSymbol ) isBlock.

What happens in most of the code is objects generate block closures which
they then set as the values of other object's properties. The code ends up
looking like this toy example:
----
(An object named: #Casper) has: #greets: of: [ :x | Transcript show: 'Hi ',
x name , '! My name is ', self name; cr].
(An object named: #George) from: Casper.

Casper greets: George.
George greets: Casper.

Casper has: #greets: of: [ :x | Transcript show: 'Goodbye ', x name; cr]

Casper greets: George.
George greets: Casper.
----

And the Transcript then reads:
----
Hi George! My name is Casper
Hi Casper! My name is George
Goodbye George
Hi Casper! My name is George
----

The name and named: methods actually set key value and find key by value in
the Smalltalk dictionary, so they're globals as in editing Javascript's
window object.

But as you see, I'm passing a block closure to one object, and copying it to
another object, and both objects are referencing the same block closure!
 I'm overwriting the
original block closure's outerContext's receiver (which in this
example is originally nil!), with whatever object is referencing it.
This is similar to what happens with Javascript
method calls, where the this variable is set by hacking the scope
object at call time.  But this lets these objects respond to any
message that may come their way, and usually
do the right thing.  My original dNU used the
valueWithEnoughArugments: method, because it was the only way I could
find to neatly get all the block closures to work in both
the case of over and underflow, as their equivalent functions worked
in the JS version.

If I compile an actual method send, and dNU is not called, I then need to
always compile a method every time a property is
set, even if it is never executed.

In this application, objects inherit based on a shallow copy of object
properties.  So
you may inherit some methods using from: from one object, a bunch of others
from another,
and then override some of each of those in a third.  (This scenario actually
the norm not the exception btw!)  99% of the time, I want whatever the
values the block closure
derived from its original defining context, with the sole exception of the
outerContext's receiver, which is almost always wrong for my purposes.

I'm mostly wondering if there's a cleaner, more optimizeable way of messing
around with the internals of either the resulting MethodContext or your
closure objects :)

Dave


-- 
-=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20090708/45cebc93/attachment.htm


More information about the Squeak-dev mailing list