Overriding #class

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

Overriding #class

Martin Beck-3
Hello,

we have a little problem while implementing a CodA meta-object protocol.
The facility we try to implement now (or first :) ) is that every
instance should have the possibility to add behaviour (i.e. methods) to
it, but not to the class. Our first approach, which was also advised in
Jeff McAffer's papers, was to insert 'anonymous' classes, which
implement these methods and change the objects class to that new foo-class.

However, to retain normal behaviour, we want to override the #class
method to return the real class of the object, not the inserted one. The
CodA metastructure will be accessed through a #meta message.

As you might have expected, our problem is now, that the compiler
optimizes the #class send and therefore the code only works in the
debugger. Our question is now, whether there is an easy and shareable
(Monticello, etc.) way to disable these optimizations and whether this
idea could work with the current VM implementation? If the VM doesn't
use the #class method to bind messages to an object to the methods of
its class, we think that it could be possible, but if this lookup is not
built into the VM but rather into the ST system, we have to go another
way...

Any ideas? Maybe replacing the object which shall be extended by a
method with a proxy, catch every message and do the lookup ourselves?

Regards,
Martin

Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

Bert Freudenberg

On Nov 13, 2007, at 11:28 , Martin Beck wrote:

> Hello,
>
> we have a little problem while implementing a CodA meta-object  
> protocol. The facility we try to implement now (or first :) ) is  
> that every instance should have the possibility to add behaviour  
> (i.e. methods) to it, but not to the class. Our first approach,  
> which was also advised in Jeff McAffer's papers, was to insert  
> 'anonymous' classes, which implement these methods and change the  
> objects class to that new foo-class.
>
> However, to retain normal behaviour, we want to override the #class  
> method to return the real class of the object, not the inserted  
> one. The CodA metastructure will be accessed through a #meta message.
>
> As you might have expected, our problem is now, that the compiler  
> optimizes the #class send and therefore the code only works in the  
> debugger. Our question is now, whether there is an easy and  
> shareable (Monticello, etc.) way to disable these optimizations and  
> whether this idea could work with the current VM implementation? If  
> the VM doesn't use the #class method to bind messages to an object  
> to the methods of its class, we think that it could be possible,  
> but if this lookup is not built into the VM but rather into the ST  
> system, we have to go another way...

Wouldn't overriding #class break more things than it solves? After  
all, your object's class is not what it would claim to be.

Which "normal behavior" would you like to "retain"?

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

Martin Beck-3
Bert Freudenberg schrieb:
>
> Wouldn't overriding #class break more things than it solves? After all,
> your object's class is not what it would claim to be.
>
> Which "normal behavior" would you like to "retain"?
Infact, we don't want to override Object>>#class but the #class in our
generated anonymous class. It would look like this:

AnonymousClass>>#class
        ^self baseClass

So normal system behaviour is not changed, only if you alter an instance
by for example adding a method, an anonymous class in the class chain is
inserted which overrides the #class method. One reason to do this, is
that the CodA paper specifies this behaviour, too. Another one would be,
if somewhere in the system instances are tested for their classes (which
shouldn't be the case...).

But it seems, that this is not possible in an easy way...

Regards,
Martin

Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

Bryce Kampjes
Martin Beck writes:
 > Bert Freudenberg schrieb:
 > >
 > > Wouldn't overriding #class break more things than it solves? After all,
 > > your object's class is not what it would claim to be.
 > >
 > > Which "normal behavior" would you like to "retain"?
 > Infact, we don't want to override Object>>#class but the #class in our
 > generated anonymous class. It would look like this:
 >
 > AnonymousClass>>#class
 > ^self baseClass
 >
 > So normal system behaviour is not changed, only if you alter an instance
 > by for example adding a method, an anonymous class in the class chain is
 > inserted which overrides the #class method. One reason to do this, is
 > that the CodA paper specifies this behaviour, too. Another one would be,
 > if somewhere in the system instances are tested for their classes (which
 > shouldn't be the case...).

I'd suggest disabling the bytecode that implements the class message.
It doesn't do a message look-up. You could do this either by
converting the bytecode to a normal send (there's several bytecodes
that just do sends so this should be easy) or by modifying the
compiler to generate a normal send bytecode with a selector in the
literal frame.

I doubt that disabling this optimisation will cause problems but
could be wrong.

Bryce

Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

ccrraaiigg

Hi--

 > I'd suggest disabling the bytecode that implements the class message.
 > It doesn't do a message look-up. You could do this either by
 > converting the bytecode to a normal send (there's several bytecodes
 > that just do sends so this should be easy) or by modifying the
 > compiler to generate a normal send bytecode with a selector in the
 > literal frame.
 >
 > I doubt that disabling this optimisation will cause problems but
 > could be wrong.

      I did this for Spoon's proxy system, and it seems to work fine.


-C

--
Craig Latta
www.netjam.org



Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

Andreas.Raab
Craig Latta wrote:

>  > I'd suggest disabling the bytecode that implements the class message.
>  > It doesn't do a message look-up. You could do this either by
>  > converting the bytecode to a normal send (there's several bytecodes
>  > that just do sends so this should be easy) or by modifying the
>  > compiler to generate a normal send bytecode with a selector in the
>  > literal frame.
>  >
>  > I doubt that disabling this optimisation will cause problems but
>  > could be wrong.
>
>      I did this for Spoon's proxy system, and it seems to work fine.

Oh, interesting. Did you ever run the macro benchmarks to see how much
of a difference that makes? I've always wondered about the speed impact
in a realistic kind of setting.

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

stephane ducasse
In reply to this post by Martin Beck-3
Hi martin

this is fun. I did that in VW and it worked like you mention (see my  
JOOP Message passing control in Smalltalk).
I defined class to return the superclass (if I remember correctly)  
and meta object to return the class.
Then I could get instance based control as in Coda. Now in Squeak the  
ideas developed in the paper could
not be implemented because class was not redefinable :(

Stef

On 13 nov. 07, at 11:28, Martin Beck wrote:

> Hello,
>
> we have a little problem while implementing a CodA meta-object  
> protocol. The facility we try to implement now (or first :) ) is  
> that every instance should have the possibility to add behaviour  
> (i.e. methods) to it, but not to the class. Our first approach,  
> which was also advised in Jeff McAffer's papers, was to insert  
> 'anonymous' classes, which implement these methods and change the  
> objects class to that new foo-class.
>
> However, to retain normal behaviour, we want to override the #class  
> method to return the real class of the object, not the inserted  
> one. The CodA metastructure will be accessed through a #meta message.
>
> As you might have expected, our problem is now, that the compiler  
> optimizes the #class send and therefore the code only works in the  
> debugger. Our question is now, whether there is an easy and  
> shareable (Monticello, etc.) way to disable these optimizations and  
> whether this idea could work with the current VM implementation? If  
> the VM doesn't use the #class method to bind messages to an object  
> to the methods of its class, we think that it could be possible,  
> but if this lookup is not built into the VM but rather into the ST  
> system, we have to go another way...
>
> Any ideas? Maybe replacing the object which shall be extended by a  
> method with a proxy, catch every message and do the lookup ourselves?
>
> Regards,
> Martin
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

hernan.wilkinson
In reply to this post by Martin Beck-3
Hi Martin,
 even though you change the implementation of the message #class, the behavior you expect will not work because the method lookup algorithm access the class field of the object header directly. So, what you really need is a way to change that field, like a primitive (something VisualWorks and VisualAge have. I don't know about Squeak...)
 Alejandra De Bonnis has implemented instance behavior as part of her master's thesis, adding a new field to the object header that points to a "message reception strategy" and changing the VM's method lookup in this way:
1) If the receiver's message reception strategy IS NOT nil, send the message #value: to the message reception strategy with the original message as argument (*).
2) If the receiver's message reception strategy IS nil, and the receiver's class message reception strategy IS NOT nil, send the message #value: to the receiver's class message reception strategy with the original message as argument (**).
3) Else, execute the normal method lookup (GLC in case of Squeak).

(*) The message reception strategy is a "first class object". That means that you can implement in Smalltalk the behavior an object should have when receiving a message. It also means that special care had to be taken to avoid an endless loop. Our decision was to prohibit to specify a message reception strategy for those objects that represent a message reception strategy.
(**) We did this because we wanted also the possibility to change the behavior of all instances of a class at once.

I don't remember the right numbers on performance, but the impact was not big at all when no special behavior was configured.
About memory, a word for each object was added, not that bad...
She created some specials tools to manipulate this characteristics (inspectors or browsers,  I don't remember exactly)

If you want, we can provide you the image, vm source code, etc.
IMHO, changing the VM is the best way to implement instance behavior, no need to rely on DNU, proxies, etc. This approach reifies message reception, therefore you can do what ever you want when an object receives a message.

Bye,
Hernan.


 What we did is:
1) Add a new field to the objetct


On Nov 13, 2007 7:56 AM, Martin Beck <[hidden email]> wrote:
Bert Freudenberg schrieb:
>
> Wouldn't overriding #class break more things than it solves? After all,
> your object's class is not what it would claim to be.
>
> Which "normal behavior" would you like to "retain"?
Infact, we don't want to override Object>>#class but the #class in our
generated anonymous class. It would look like this:

AnonymousClass>>#class
       ^self baseClass

So normal system behaviour is not changed, only if you alter an instance
by for example adding a method, an anonymous class in the class chain is
inserted which overrides the #class method. One reason to do this, is
that the CodA paper specifies this behaviour, too. Another one would be,
if somewhere in the system instances are tested for their classes (which
shouldn't be the case...).

But it seems, that this is not possible in an easy way...

Regards,
Martin




Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

ccrraaiigg
In reply to this post by Andreas.Raab

 > Oh, interesting. Did you ever run the macro benchmarks to see how much
 > of a difference that makes? I've always wondered about the speed
 > impact in a realistic kind of setting.

      Ah, in normal use there's just an additional check to see if the
class of the receiver is the proxy class (which is in the special
objects array). The effect on the macro benchmarks was undetectable.
When proxies are involved, the network overhead of sending remote
messages swamps the slowdown caused by invoking the normal sends.

      So, not the test you were hoping for. :)


-C

--
Craig Latta
improvisational musical informaticist
www.netjam.org
Smalltalkers do: [:it | All with: Class, (And love: it)]


Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

Martin Beck-3
In reply to this post by ccrraaiigg
Hi Craig,
thanks for your answers. Do you or anyone else have a simple hint, where
in the compiler we can turn off this optimization? It is very hard to
debug the parser/compiler to find the correct place... :(

Regards,
Martin

Craig Latta wrote:

>
> Hi--
>
>  > I'd suggest disabling the bytecode that implements the class message.
>  > It doesn't do a message look-up. You could do this either by
>  > converting the bytecode to a normal send (there's several bytecodes
>  > that just do sends so this should be easy) or by modifying the
>  > compiler to generate a normal send bytecode with a selector in the
>  > literal frame.
>  >
>  > I doubt that disabling this optimisation will cause problems but
>  > could be wrong.
>
>      I did this for Spoon's proxy system, and it seems to work fine.
>
>
> -C
>
> --
> Craig Latta
> www.netjam.org
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Overriding #class

ccrraaiigg

Hi Martin--

 > ...where in the compiler we can turn off this optimization? It is very
 > hard to debug the parser/compiler to find the correct place... :(

      Oh, I didn't change the compiler, I changed
Interpreter>>bytecodePrimClass (see below) and rebuilt the interpreter.


      have fun,

-C

***

Interpreter>>bytecodePrimClass
      | receiver receiverClass |

      receiver := self internalStackTop.
      receiverClass := self fetchClassOf: receiver.
      (receiverClass = (self splObj: ClassProxy)) ifFalse: [
           self internalPop: 1 thenPush: receiverClass.
           ^self fetchNextBytecode].
      messageSelector := self specialSelector: 23.
      argumentCount := 0.
      self normalSend

--
Craig Latta
www.netjam.org