[squeak-dev] A question about block closures.

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

[squeak-dev] A question about block closures.

David Goehrig
Dear Squeakers,

I have a question for some of Squeak gurus on the list.  I've been porting a javascript project I did a couple months back to Squeak, and in the process of porting it, added an ad hoc object class that handled the prototype based inheritance I used in the javascript version.

One of the issues I encountered was that when I did a copy of my object, the block closures supplied for various properties required a bit of a hack so I have a method:

doesNotUnderstand: aMessage
"Generic catch all that performs all selectors"
(self can: aMessage selector) ifTrue: [ 
(self s: aMessage selector ) outerContext receiver: self. 
^( self s: aMessage selector )valueWithEnoughArguments: aMessage arguments ].
^ self s: aMessage selector.

Now this seems to do exactly what I wanted 99% of the time.  It mimics the behavior of using a block closure as a javascript function() {} object, and all other objects are returned as intended.  The #s: method returns nil if the property is not found in the object's dictionary as well, and #can: is just a fancy way to test if the property is a block closure.  By using valueWithEnoughArguments: it even gets padded out with nils like JS would.

I'm not entirely happy with how hackish this seems, patching the outerContext and then re-rolling the arguments array to one of the proper size just to copy into a MethodContext. 

My question is "Is there a better way?"

Dave

--
-=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

Eliot Miranda-2


On Tue, Jul 7, 2009 at 3:58 PM, David Goehrig <[hidden email]> wrote:
Dear Squeakers,

I have a question for some of Squeak gurus on the list.  I've been porting a javascript project I did a couple months back to Squeak, and in the process of porting it, added an ad hoc object class that handled the prototype based inheritance I used in the javascript version.

One of the issues I encountered was that when I did a copy of my object, the block closures supplied for various properties required a bit of a hack so I have a method:

doesNotUnderstand: aMessage
"Generic catch all that performs all selectors"
(self can: aMessage selector) ifTrue: [ 
(self s: aMessage selector ) outerContext receiver: self. 
^( self s: aMessage selector )valueWithEnoughArguments: aMessage arguments ].
^ self s: aMessage selector.

Now this seems to do exactly what I wanted 99% of the time.  It mimics the behavior of using a block closure as a javascript function() {} object, and all other objects are returned as intended.  The #s: method returns nil if the property is not found in the object's dictionary as well, and #can: is just a fancy way to test if the property is a block closure.  By using valueWithEnoughArguments: it even gets padded out with nils like JS would.

I'm not entirely happy with how hackish this seems, patching the outerContext and then re-rolling the arguments array to one of the proper size just to copy into a MethodContext. 

My question is "Is there a better way?"

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?

You can then adapt this pattern and compile adaptors on the fly to something like

doesNotUnderstand: aMessage
"Generic catch all that performs all selectors"
(self can: aMessage selector) ifTrue:
[self compile: (self adapt: aMessage selector to: (self s: aMessage selector) classified: #'message adaptors'.
^self perform: aMessage selector withArguments: aMessage arguments

or

doesNotUnderstand: aMessage
"Generic catch all that performs all selectors"
(self can: aMessage selector) ifTrue:
[self compileAdaptorFor: aMessage selector to: (self s: aMessage selector).
^self perform: aMessage selector withArguments: aMessage arguments

so the doesNotUnderstand: would be invoked first-time only (echos of the Borning-Ingalls multiple inheritance implementation). adapt:to: would return the text of a method that supplied nils for missing arguments (note it is pretty trivial to add default values with this pattern). Decorate the method with a pragma to mark it as auto-generated, e.g. adapt: #myMessage: to: #myMessage:with: might answer
'myMessage: arg1
<adaptorFor: #myMessage:with:>
^self myMessage: arg1 with: nil'

Then you can easily flush generated adaptors (e.g. before writing out an MC package, could also merely use the category to corral adaptors).

Yes?

best
Eliot

Dave

--
-=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/






Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

David Goehrig


On Wed, Jul 8, 2009 at 2:04 AM, Eliot Miranda <[hidden email]> 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/


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

Igor Stasenko
In reply to this post by David Goehrig
David, have you tried to use/evaluate a Prototype package for own purposes?

http://wiki.squeak.org/squeak/1369

2009/7/8 David Goehrig <[hidden email]>:

> Dear Squeakers,
> I have a question for some of Squeak gurus on the list.  I've been porting a
> javascript project I did a couple months back to Squeak, and in the process
> of porting it, added an ad hoc object class that handled the prototype based
> inheritance I used in the javascript version.
> One of the issues I encountered was that when I did a copy of my object, the
> block closures supplied for various properties required a bit of a hack so I
> have a method:
> doesNotUnderstand: aMessage
> "Generic catch all that performs all selectors"
> (self can: aMessage selector) ifTrue: [
> (self s: aMessage selector ) outerContext receiver: self.
> ^( self s: aMessage selector )valueWithEnoughArguments: aMessage arguments
> ].
> ^ self s: aMessage selector.
> Now this seems to do exactly what I wanted 99% of the time.  It mimics the
> behavior of using a block closure as a javascript function() {} object, and
> all other objects are returned as intended.  The #s: method returns nil if
> the property is not found in the object's dictionary as well, and #can: is
> just a fancy way to test if the property is a block
> closure.  By using valueWithEnoughArguments: it even gets padded out with nils like JS would.
> I'm not entirely happy with how hackish this seems, patching the outerContext and then re-rolling the arguments array to one of the proper size just to copy into a MethodContext.
> My question is "Is there a better way?"
> Dave
> --
> -=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/
>
>
>
>



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

David Goehrig
Yes actually both of those. Russel's work was part of the inspiration  
behind the js code I am porting. But I am not happy with what they did.

Don't get me wrong. What I did works 99% of the time. I'm just afraid  
that the next step involves some additional vm hacks.

-=-=- [hidden email] -=-=-

On Jul 8, 2009, at 8:01 AM, Igor Stasenko <[hidden email]> wrote:

> David, have you tried to use/evaluate a Prototype package for own  
> purposes?
>
> http://wiki.squeak.org/squeak/1369
>
> 2009/7/8 David Goehrig <[hidden email]>:
>> Dear Squeakers,
>> I have a question for some of Squeak gurus on the list.  I've been  
>> porting a
>> javascript project I did a couple months back to Squeak, and in the  
>> process
>> of porting it, added an ad hoc object class that handled the  
>> prototype based
>> inheritance I used in the javascript version.
>> One of the issues I encountered was that when I did a copy of my  
>> object, the
>> block closures supplied for various properties required a bit of a  
>> hack so I
>> have a method:
>> doesNotUnderstand: aMessage
>> "Generic catch all that performs all selectors"
>> (self can: aMessage selector) ifTrue: [
>> (self s: aMessage selector ) outerContext receiver: self.
>> ^( self s: aMessage selector )valueWithEnoughArguments: aMessage  
>> arguments
>> ].
>> ^ self s: aMessage selector.
>> Now this seems to do exactly what I wanted 99% of the time.  It  
>> mimics the
>> behavior of using a block closure as a javascript function() {}  
>> object, and
>> all other objects are returned as intended.  The #s: method returns  
>> nil if
>> the property is not found in the object's dictionary as well, and  
>> #can: is
>> just a fancy way to test if the property is a block
>> closure.  By using valueWithEnoughArguments: it even gets padded  
>> out with nils like JS would.
>> I'm not entirely happy with how hackish this seems, patching the  
>> outerContext and then re-rolling the arguments array to one of the  
>> proper size just to copy into a MethodContext.
>> My question is "Is there a better way?"
>> Dave
>> --
>> -=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/
>>
>>
>>
>>
>
>
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

Eliot Miranda-2
In reply to this post by David Goehrig


On Wed, Jul 8, 2009 at 4:53 AM, David Goehrig <[hidden email]> wrote:


On Wed, Jul 8, 2009 at 2:04 AM, Eliot Miranda <[hidden email]> 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 :)

Well the obvious way to clean up those closures is to pass the self reference as an argument, so

(An object named: #Casper) has: #greets: of: [ :theSelf :x | Transcript show: 'Hi ', x name , '! My name is ', theSelf name; cr].

and

doesNotUnderstand: aMessage
"Generic catch all that performs all selectors"
(self can: aMessage selector) ifTrue:
[^( self s: aMessage selector ) valueWithEffectiveReceiver: self andEnoughArguments: aMessage arguments ].
^ self s: aMessage selector.

and for a little bit of extra efficiency I would combine can: and s:, e.g.

doesNotUnderstand: aMessage
"Generic catch all that performs all selectors"
^(self s: aMessage selector)
ifNotNil: [:block| block valueWithEffectiveReceiver: self andEnoughArguments: aMessage arguments]
ifNil: [self s: aMessage selector]


As regards more generic property handling I don't know of a better way than the doesNotUnderstand: handler for handling properties held in per-instance dictionaries if the constraint is that you definitely don't want to compile accessors for the property and you are using the vanilla VM.  You would indeed need to modify the VM to provide for a cheap property accessor, for example, being able to add something as the value in a method dictionary that said "invoke this selector with the actual selector as an additional argument", so in the method dictionary you would have (avoiding support for varargs)

    myProperty -> { #getProperty: } asPropertyAccessorThingy
    myProperty: -> { #setProperty:to: } asPropertyAccessorThingy
    myMoreGenericFunction:with: -> { #evaluateGenericProperty:with:with: } asPropertyAccessorThingy

etc and

MyPrototypeObject getProperty: propertyName
         ^properties at: propertyName ifAbsent: [parent getProperty: propertyName]

etc


But methods are cheap and so I don't see the benefit of avoiding methods in favour of blocks.  When one uses mehtods all sorts of optimizations are enabled, such as efficiently mapping high-dynamic-frequency properties to slots a la V8.  Vassili Bykov, Claus Gittinger and I did a prototype JavaScript implementation in Smalltalk in the summer of 2006 which did this and it was fast.  Vassili came up with the great idea of generating bytecode for slot accessors directly and minting a set of 256 accessors that traversed the parent chain in a loop.  Effectively each accessor method looked like

accessSlot0
    | object |
    object := self.
    [object slot0 ifNotNil: [:value| ^value].
     (object := object parentSlot) ~~ nil] whileTrue.
    ^#undefined

The closure bytecode pushTemp:inVectorAt: can be used to fetch an arbitrary slot of an object held in a temporary and so is used to implement object slotN and object parentSlot.

Both Claus Gittinger and Dan Ingalls have had the idea of creating an object that is an instance of itself.  One way, without VM mods (and ignoring issues with compact classes), is to do something like

prototype: aPrototype numNewSlots: numNewSlots
    | format object |
    object := (Array new: aPrototype numberOfSlots + numNewSlots + 3).
    object
         at: 1 "superclass" put: aPrototype;
         at: 2 "methods"    put: MethodDictionary new;
         at: 3 "format"       put: (self formatOf: aPrototype format withAdditionalSlots: numNewSlots).
   object changeClassTo: object.
   ^object

If one flattens MethodDictionary into an array of pairs, which is good for space and even faster for lookup for most dictionaries, because they're small, and linear scan is fast, then nil looks like an empty method dictionary.  Then a primitive implementation is no more than a single allocation that fills in the prototype and format slots and sets the class.

Combine one with the other and you have the potential for a lean and mean prototype-based system using the existing VM technology, which would mean an efficient JavaScript implementation within Smalltalk.
 
so much to do and so little time ;)

best
Eliot

Dave


--
-=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/



Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: A question about block closures.

Klaus D. Witzel
On Wed, 08 Jul 2009 18:55:28 +0200, Eliot Miranda wrote:

> As regards more generic property handling I don't know of a better way  
> than
> the doesNotUnderstand: handler for handling properties held in  
> per-instance
> dictionaries if the constraint is that you definitely don't want to  
> compile
> accessors for the property and you are using the vanilla VM.

I'm using this:

  (Object methodDict at: #aSymbol flushCache put: #name -> #value).
  (Object aSymbol)

and the VM then sends (in this example) to the Association

anAssociation>>run: #aSymbol with: #() in: Object

This is (AFAIK) from/for ObjectAsMethod in the "vanilla" VM. But beware,  
don't put a small int, then the VM crashes

- http://bugs.squeak.org/view.php?id=7157

/Klaus

...


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

David Goehrig
In reply to this post by Eliot Miranda-2


On Wed, Jul 8, 2009 at 12:55 PM, Eliot Miranda <[hidden email]> wrote:
Well the obvious way to clean up those closures is to pass the self reference as an argument, so

(An object named: #Casper) has: #greets: of: [ :theSelf :x | Transcript show: 'Hi ', x name , '! My name is ', theSelf name; cr].

That's an even worse hack. :)
 
doesNotUnderstand: aMessage
"Generic catch all that performs all selectors"
(self can: aMessage selector) ifTrue:
[^( self s: aMessage selector ) valueWithEffectiveReceiver: self andEnoughArguments: aMessage arguments ].
^ self s: aMessage selector.

I take it you'd have to define #valueWithEffectiveReceiver:andEnoughArguments: as BlockClosure has no such beast.  If  the closure was promoted to a CompiledMethod, then I guess you could use #valueWithReceiver:arguments: and another patched Array.  Or did I miss something?
 
As regards more generic property handling I don't know of a better way than the doesNotUnderstand: handler for handling properties held in per-instance dictionaries if the constraint is that you definitely don't want to compile accessors for the property and you are using the vanilla VM.

I figured the dNU approach was close enough to what Morphic did, that it was "good enough".  But I was surprised how 
weird the code got.

But methods are cheap and so I don't see the benefit of avoiding methods in favour of blocks.

It largely has to do with not being able to get methods to actually work :)  I originally was trying to patch in CompiledMethods but ran into too many of the blowing up in bizarre ways, and the semantics drifting too far
from the JS version of the API. 

  Vassili came up with the great idea of generating bytecode for slot accessors directly and minting a set of 256 accessors that traversed the parent chain in a loop.  Effectively each accessor method looked like

accessSlot0
    | object |
    object := self.
    [object slot0 ifNotNil: [:value| ^value].
     (object := object parentSlot) ~~ nil] whileTrue.
    ^#undefined

I have a OO Forth that does the exact same thing, except it rolls native x86 machine code :)
 
Both Claus Gittinger and Dan Ingalls have had the idea of creating an object that is an instance of itself.  One way, without VM mods (and ignoring issues with compact classes), is to do something like

prototype: aPrototype numNewSlots: numNewSlots
    | format object |
    object := (Array new: aPrototype numberOfSlots + numNewSlots + 3).
    object
         at: 1 "superclass" put: aPrototype;
         at: 2 "methods"    put: MethodDictionary new;
         at: 3 "format"       put: (self formatOf: aPrototype format withAdditionalSlots: numNewSlots).
   object changeClassTo: object.
   ^object

I did something similar with another project, but I've found doing the deep copies on the MethodDictionary ends up 
failing in weird ways.  
 
Combine one with the other and you have the potential for a lean and mean prototype-based system using the existing VM technology, which would mean an efficient JavaScript implementation within Smalltalk.

I guess I know what the next set of experiments I'm going to do are :)

Thanks Eliot for thinking through this with me.

The main reason I'm building this, is I've got this very fluid ad hoc Javascript editing environment I wrote that I'm trying to port to Squeak.  I've been writing a book on programming that runs the reader through the process of designing a simple 8bit CPU, that has been implemented as step by step drag and drop examples on top of it.  

The only problem is that the only JS + HTML5 implementation out there in the wild that can actually handle it is Safari, and I can't bundle that with the book :)

If I can get it ported to Squeak, I can add an additional appendix and give the code listings in both Smalltalk and Javascript.  But I want the code to have direct analogues, so the translations of concepts between languages are
clear.

Dave
--
-=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

Eliot Miranda-2


On Wed, Jul 8, 2009 at 11:13 AM, David Goehrig <[hidden email]> wrote:


On Wed, Jul 8, 2009 at 12:55 PM, Eliot Miranda <[hidden email]> wrote:
Well the obvious way to clean up those closures is to pass the self reference as an argument, so

(An object named: #Casper) has: #greets: of: [ :theSelf :x | Transcript show: 'Hi ', x name , '! My name is ', theSelf name; cr].

That's an even worse hack. :)

I disagree :)  Reaching into a closure's home in a completely unthread-safe manner is a horrible hack.  Using closures to implement properties is an implementation detail and one is free to compile to those closures as one sees fit.  Better to make the soft binding explicit.

But I guess (your original message wasn't clear on the subject) that what you do when you want to reuse one of these closures is that you copy the closure and its enclosing MethodContext (remember this is a chain and blocks could be nested) and assign the new receiver in the copy.  That's not too bad but its still very heavyweight because you're not sharing code between instances.

 
 doesNotUnderstand: aMessage
"Generic catch all that performs all selectors"
(self can: aMessage selector) ifTrue:
[^( self s: aMessage selector ) valueWithEffectiveReceiver: self andEnoughArguments: aMessage arguments ].
^ self s: aMessage selector.

I take it you'd have to define #valueWithEffectiveReceiver:andEnoughArguments: as BlockClosure has no such beast.  If  the closure was promoted to a CompiledMethod, then I guess you could use #valueWithReceiver:arguments: and another patched Array.  Or did I miss something?

No, that's it.  You could also write it as
    ^self evaluate: ( self s: aMessage selector ) withEffectiveReceiver: self andEnoughArguments: aMessage arguments
and have the extension in your framework not on BlockClosure.
And of course your suggestion with CompiledMethod would work.
 
 As regards more generic property handling I don't know of a better way than the doesNotUnderstand: handler for handling properties held in per-instance dictionaries if the constraint is that you definitely don't want to compile accessors for the property and you are using the vanilla VM.

I figured the dNU approach was close enough to what Morphic did, that it was "good enough".  But I was surprised how 
weird the code got.

But methods are cheap and so I don't see the benefit of avoiding methods in favour of blocks.

It largely has to do with not being able to get methods to actually work :)  I originally was trying to patch in CompiledMethods but ran into too many of the blowing up in bizarre ways, and the semantics drifting too far
from the JS version of the API. 

  Vassili came up with the great idea of generating bytecode for slot accessors directly and minting a set of 256 accessors that traversed the parent chain in a loop.  Effectively each accessor method looked like

accessSlot0
    | object |
    object := self.
    [object slot0 ifNotNil: [:value| ^value].
     (object := object parentSlot) ~~ nil] whileTrue.
    ^#undefined

I have a OO Forth that does the exact same thing, except it rolls native x86 machine code :)

Cool :)  But note that the JIT does produce x86 code for you so at the metal there's not a lot of difference :)

 
 Both Claus Gittinger and Dan Ingalls have had the idea of creating an object that is an instance of itself.  One way, without VM mods (and ignoring issues with compact classes), is to do something like

prototype: aPrototype numNewSlots: numNewSlots
    | format object |
    object := (Array new: aPrototype numberOfSlots + numNewSlots + 3).
    object
         at: 1 "superclass" put: aPrototype;
         at: 2 "methods"    put: MethodDictionary new;
         at: 3 "format"       put: (self formatOf: aPrototype format withAdditionalSlots: numNewSlots).
   object changeClassTo: object.
   ^object

I did something similar with another project, but I've found doing the deep copies on the MethodDictionary ends up 
failing in weird ways.  

But you don't need to copy the MethodDictionaries.  With the above approach they're shared/inherited.  So when a message is sent to a subinstance the lookup machinery will follow the prototype chain until it finds a method or triggers dNU.  In the activation self is bound to the original receiver.  The issue is hence making sure that slot layouts in subinstances match their parents so that parent methods work correctly on subinstances.  But that's not a new problem, Smalltalk does exactly that :)

 
 Combine one with the other and you have the potential for a lean and mean prototype-based system using the existing VM technology, which would mean an efficient JavaScript implementation within Smalltalk.

I guess I know what the next set of experiments I'm going to do are :)

Thanks Eliot for thinking through this with me.

The main reason I'm building this, is I've got this very fluid ad hoc Javascript editing environment I wrote that I'm trying to port to Squeak.  I've been writing a book on programming that runs the reader through the process of designing a simple 8bit CPU, that has been implemented as step by step drag and drop examples on top of it.  

The only problem is that the only JS + HTML5 implementation out there in the wild that can actually handle it is Safari, and I can't bundle that with the book :)

If I can get it ported to Squeak, I can add an additional appendix and give the code listings in both Smalltalk and Javascript.  But I want the code to have direct analogues, so the translations of concepts between languages are
clear.

Please keep me in the loop.  This is interesting and I'm happy to review.

cheers
Eliot
 

Dave
--
-=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/






Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

David Goehrig


On Wed, Jul 8, 2009 at 2:30 PM, Eliot Miranda <[hidden email]> wrote:

ur original message wasn't clear on the subject) that what you do when you want to reuse one of these closures is that you copy the closure and its enclosing MethodContext (remember this is a chain and blocks could be nested) and assign the new receiver in the copy.  That's not too bad but its still very heavyweight because you're not sharing code between instances.

No I actually am using the chain as is, and counting on the fact that these blocks are nested.   The only tricksy bit is
you can't actually use ^ in the BlockClosures or you run into the sender's context no longer exists error :)  I'm exploiting
the fact that you can hard ref them, and keep the garbage collector from scavaging them.
 
But you don't need to copy the MethodDictionaries.  With the above approach they're shared/inherited.  So when a message is sent to a subinstance the lookup machinery will follow the prototype chain until it finds a method or triggers dNU.

Ah that's one thing I need to explain.  There's no prototype chain!   Each object is standalone with copies of closures from 2 or more objects.  Some of those closures are actually generated on the fly, and orphaned from their original context.  Prototyping doesn't work, when you need partial inheritance from multiple objects!

For example, I have a method called "which:" which performs a test upon each property of an object, and returns a new
object instance with only those properties.  Often I use this to do things like take the intersection of two objects, ie inherit those properties which are common to two arbitrary parents, and then extend using a 3rd archetype.

So I actually do need to copy MethodDictionaries, as objects often alter their own and others periodically at runtime.  For example, the implementation of a method #draw may change over time, as an animation timer swaps out new
BlockClosures for each frame in the animation.  Some times the #down event that is dispatch to all widgets get replace based on the application state, rather than performing checks within the method.
 
 In the activation self is bound to the original receiver.  The issue is hence making sure that slot layouts in subinstances match their parents so that parent methods work correctly on subinstances.  But that's not a new problem, Smalltalk does exactly that :)

Yeah, that becomes a huge problem, as I often remove slots from children that exist in the parent objects.  And since
these are ad hoc objects, there's no set relationship between parent and child.  An object may derive from one object,
and then at a later date, serve as reference for the object that was its parent, such as:
  
A -> B -> C 
              &D -> A

A is now A's own great grandson.  B doesn't however derive any changes from C, as it has its own copy of each property.

The Javascript version of this code doesn't even use prototype based inheritance!  The idea behind this sort of 
unstructured Object Oriented programming is "object sex".    You treat each object as a stand alone entity, that
can swap out its genes with other objects as necessary.  So it isn't "prototype" based in the traditional sense, it
is more archetype based with ad hoc morphology.
 
Please keep me in the loop.  This is interesting and I'm happy to review.

Very cool, will do!

Dave 
--
-=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] A question about block closures.

Igor Stasenko
In reply to this post by Eliot Miranda-2
2009/7/8 Eliot Miranda <[hidden email]>:
>
>
[snip]

> Please keep me in the loop.  This is interesting and I'm happy to review.

+1. Indeed. Very interesting

> cheers
> Eliot
>
>>
>> Dave
>> --
>> -=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/
>>




--
Best regards,
Igor Stasenko AKA sig.