I was thinking about implementing a Proxy but instead the usual way which I believe is subclassing from ProtoObject, I subclassed from Object a ProxyObject with an iVar called encapsulatedObject, and then write
ProxyObject >>doesNotUnderstand: aMessage ^aMessage sendTo: self encapsulatedObject
Then for every message I need to intercept, I write:
ProxyObject >>at: index put: value ^self doesNotUnderstand: (Message selector: #at:put: arguments: (Array with: index with: value)).
ProxyObject>>asString ^self doesNotUnderstand: (Message selector: #asString).
ProxyObject>>name ^self doesNotUnderstand: (Message selector: #name).
....
ok... you get the idea. But I was reading a paper called "Evaluating Message Passing Control Techniques in Smalltalk" from Stéphane Ducasse, and supposed my idea qualified as "minimal object". He wrote:
"The right technique to create a minimal object is the following: (1) creation of a subclass of Object, (2) assignment of the superclass link to nil and (3) definition of the minimal behavior by copying the needed methods from Object"
But I've implemented it without (2) and doing some message replication mentioned above (currently I have no more than 15 of those kind of messages) it would, at first, bypass the problem described in the "Problems" section:
"This leads to the problem of the interpretation by the minimal object of messages that were initially destined for the controlled object"
Hope I've understood the right way. However, something still smells bad to me... and that's why I'm writing to the list for some advice or suggestion. The only real problem I've experimented is when the replication of #ifNil: nilBlock takes place, this doesn't seem to work:
ProxyObject>>ifNil: nilBlock ^self doesNotUnderstand: (Message selector: #ifNil: argument: nilBlock).
(my guess here is there's some optimization thing walking around)
So, for those cool guys here, can you tell me if there is a possible drawback or unwanted behavior I'm not seeing? If true in which case would happen? Is this a valid way of implementing a Proxy or there's something I've missing? (I suspect a performance penalty, but I'm not sure about this)
I'm using a 3.9 image and VM.
Cheers
On Sep 27, 2007, at 9:46 PM, Alejandro Martínez wrote:
I was thinking about implementing a Proxy but instead the usual way which I believe is subclassing from ProtoObject, I subclassed from Object a ProxyObject with an iVar called encapsulatedObject, and then write
ProxyObject >>doesNotUnderstand: aMessage ^aMessage sendTo: self encapsulatedObject
Then for every message I need to intercept, I write:
ProxyObject >>at: index put: value ^self doesNotUnderstand: (Message selector: #at:put: arguments: (Array with: index with: value)).
There's no need to do this kind of thing. If your ProxyObject class doesn't implement #at:put: the VM will create the Message object for you and send #doesNotUnderstand: to your proxy. You only need to implement the messages you *don't* want forwarded.
Colin
Colin Putney schrieb:
On Sep 27, 2007, at 9:46 PM, Alejandro Martínez wrote:
I was thinking about implementing a Proxy but instead the usual way which I believe is subclassing from ProtoObject, I subclassed from Object a ProxyObject with an iVar called encapsulatedObject, and then write
ProxyObject >>doesNotUnderstand: aMessage ^aMessage sendTo: self encapsulatedObject
Then for every message I need to intercept, I write:
ProxyObject >>at: index put: value ^self doesNotUnderstand: (Message selector: #at:put: arguments: (Array with: index with: value)).
There's no need to do this kind of thing. If your ProxyObject class doesn't implement #at:put: the VM will create the Message object for you and send #doesNotUnderstand: to your proxy. You only need to implement the messages you *don't* want forwarded.
Colin
That's not correct in his situation - since #at:put: is implemented in the superclass (Object) it will be used. Your approach works only if he subclasses from ProtoObject. Alejandro, the information you got from Stephane's book is probably a bit outdated (we would have done it that way in the old days). The ProtoObject approach is cleaner since ProtoObject implements only those messages which are considered necessary in any object in the system. Looking at it in the browser, I think it still implements too much, so you still would have to implement some messages in your ProxyObject.
Cheers, Hans-Martin
For a worked example check out Magma
http://www.squeaksource.com/Magma
in particular the proxy support package
Keith
Exactly right. As a side note, if we would stop adding methods to ProtoObject we wouldn't need to implement them on our proxy subclasses to simulate a DNU. #ifNil:, #ifNotNil: and other convenience methods totally go against the nature of ProtoObject.
On 9/28/07, Hans-Martin Mosner hmm@heeg.de wrote:
Colin Putney schrieb:
On Sep 27, 2007, at 9:46 PM, Alejandro Martínez wrote:
I was thinking about implementing a Proxy but instead the usual way which I believe is subclassing from ProtoObject, I subclassed from Object a ProxyObject with an iVar called encapsulatedObject, and then write
ProxyObject >>doesNotUnderstand: aMessage ^aMessage sendTo: self encapsulatedObject
Then for every message I need to intercept, I write:
ProxyObject >>at: index put: value ^self doesNotUnderstand: (Message selector: #at:put: arguments: (Array with: index with: value)).
There's no need to do this kind of thing. If your ProxyObject class doesn't implement #at:put: the VM will create the Message object for you and send #doesNotUnderstand: to your proxy. You only need to implement the messages you *don't* want forwarded.
Colin
That's not correct in his situation - since #at:put: is implemented in the superclass (Object) it will be used. Your approach works only if he subclasses from ProtoObject. Alejandro, the information you got from Stephane's book is probably a bit outdated (we would have done it that way in the old days). The ProtoObject approach is cleaner since ProtoObject implements only those messages which are considered necessary in any object in the system. Looking at it in the browser, I think it still implements too much, so you still would have to implement some messages in your ProxyObject.
Cheers, Hans-Martin
Colin Putney wrote:
On Sep 27, 2007, at 9:46 PM, Alejandro Martínez wrote:
I was thinking about implementing a Proxy but instead the usual way which I believe is subclassing from ProtoObject, I subclassed from Object a ProxyObject with an iVar called encapsulatedObject, and then write
ProxyObject >>doesNotUnderstand: aMessage ^aMessage sendTo: self encapsulatedObject
Then for every message I need to intercept, I write:
ProxyObject >>at: index put: value ^self doesNotUnderstand: (Message selector: #at:put: arguments: (Array with: index with: value)).
There's no need to do this kind of thing. If your ProxyObject class doesn't implement #at:put: the VM will create the Message object for you and send #doesNotUnderstand: to your proxy. You only need to implement the messages you *don't* want forwarded.
I think the problem is exactly that he's not subclassing ProtoObject. So, #at:put: will go to a primitive instead of being trapped.
Paolo
On 9/28/07, Alejandro Martínez alemartinez2112@gmail.com wrote:
I was thinking about implementing a Proxy but instead the usual way which I believe is subclassing from ProtoObject, I subclassed from Object a ProxyObject with an iVar called encapsulatedObject, and then write
ProxyObject >>doesNotUnderstand: aMessage ^aMessage sendTo: self encapsulatedObject
Then for every message I need to intercept, I write:
ProxyObject >>at: index put: value ^self doesNotUnderstand: (Message selector: #at:put: arguments: (Array with: index with: value)).
ProxyObject>>asString ^self doesNotUnderstand: (Message selector: #asString).
ProxyObject>>name ^self doesNotUnderstand: (Message selector: #name).
....
ok... you get the idea. But I was reading a paper called "Evaluating Message Passing Control Techniques in Smalltalk" from Stéphane Ducasse, and supposed my idea qualified as "minimal object". He wrote:
"The right technique to create a minimal object is the following: (1) creation of a subclass of Object, (2) assignment of the superclass link to nil and (3) definition of the minimal behavior by copying the needed methods from Object"
But I've implemented it without (2) and doing some message replication mentioned above (currently I have no more than 15 of those kind of messages) it would, at first, bypass the problem described in the "Problems" section:
"This leads to the problem of the interpretation by the minimal object of messages that were initially destined for the controlled object"
Hope I've understood the right way. However, something still smells bad to me... and that's why I'm writing to the list for some advice or suggestion. The only real problem I've experimented is when the replication of #ifNil: nilBlock takes place, this doesn't seem to work:
ProxyObject>>ifNil: nilBlock ^self doesNotUnderstand: (Message selector: #ifNil: argument: nilBlock).
(my guess here is there's some optimization thing walking around)
So, for those cool guys here, can you tell me if there is a possible drawback or unwanted behavior I'm not seeing? If true in which case would happen? Is this a valid way of implementing a Proxy or there's something I've missing? (I suspect a performance penalty, but I'm not sure about this)
Hi Alejandro
I've got a pre-packaged, working version of a proxy. I've spent a long time trying to get it to work without crashing inspectors and debuggers, and it's still not perfect. Give it a try if you want:
http://www.squeaksource.com/DPON/MessageCapture-mvdg.9.mcz
Gulik.
squeak-dev@lists.squeakfoundation.org