Hello. I finished new version of Ghost: - DNU approach for basic proxies instead of #cannotInterpret: trick (trick used only for class proxies) - Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. - GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler. - GHGhostBehaviour should define #currentMetaLevel to specify set of messages which should not be intercepted. Such meta messages will be executed under ghost instance by subclass of GHMetaMessages. In previous version there was dictionary which maps meta message selector to implementation selector. It was not suitable. Now meta messages should be directly implemented on particular GHMetaMessages subclass and all it methods are considered meta. So GhostBehaviour should return instance of GHMetaLevel with meta messages implementation class: - GHMetaLevel with: GHEmptyMetaMessages "when all possible messages should intercepted" - GHMetaLevel with: GHStandartMetaMessages "when tools specific messages should not be intercepted" For example standard meta messages implements #inspect: GHStandartMetaMessages>>inspect "Create and schedule an Inspector in which the user can examine the receiver's variables." ^ Smalltalk tools inspector inspect: *ghost* - Traits for methods explicitly defined on ghosts: TMinimalProxy, TNotNilProxy, TIdentifiedProxy (with #=, #hash, #class). Concrete proxies can add this traits to itself independently from meta level. For example traits supply convenient methods to retrieve ghost information in polymorphic way with objects: - ghost isGhost - ghost ghostClass "returns actual class of receiver" - ghost ghostPrintString "returns string which represents ghost from meta level point of view" This traits are suitable and they provide some kind of optimisation for proxies (methods from traits are executed directly instead of complex meta messages mechanizm). But maybe they are superfluous. For example they can't be reused for class proxies which substitute real object classes (to intercept all instance messages). - GHClassGhost able to replace class of real objects. It implements cannotInterpret: trick to intercept all instance messages. Subclasses should define two behaviours: #ghostBehaviour (as any other ghost) and #instancesBehaviour which will process instance messages. In previous version it was different message to same #ghostBehaviour. - New kind of proxies: - GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim class. So in case when virus is created with standard meta level tools will not differ him from health object. There are special messages which allow ask object about viruses: - infectedObject isInfectedByVirus - infectedObject virus - infectedObject recoverFromVirus - GHLearningObject. It is suitable proxy which retrieves all unknown methods from teacher class. Thank's Stephan for this idea. This kind of proxy allows me easily find required set of messages to support inspectors and debuggers. You can create instance of learning object by: GHLearningObject withTeacher: Object. And any operation with it will fill studiedMessages dictionary. In my case I opened GTInspector on it and got all messages which was needed for him. - Ghosts works correctly with latest Pharo 5 tools (basic inspector, GTInspector, SpecDebugger, GTDebugger). Required methods for tools are extracted to 'Ghost-GTSupport' package. - Repackaging: - Ghost-ObjectProxies. It contains all core classes and abstract GHObjectGhost which is based on DNU - Ghost-ClassProxies. It contains code for proxy which can substitute class of real object. GHClassGhost implements cannotInterpret: trick to intercept all instance messages. And it implement support for debugging such methods. - Ghost-LearningObject - Ghost-ObjectVirus - Ghost-GTSupport - test packages - All code moved to Pharo repository http://smalltalkhub.com/#!/~Pharo/Ghost (in includes packages from CAR repo too) You can load new version by: Gofer it smalltalkhubUser: 'Pharo' project: 'Ghost'; configurationOf: 'Ghost'; loadStable I use it now in Seamless and Mocketry.
Awesome. Things are looking good. Now, just have to find time to use all of this :-) Phil On Thu, Mar 24, 2016 at 5:48 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
Hello.
I finished new version of Ghost:
- DNU approach for basic proxies instead of #cannotInterpret: trick (trick used only for class proxies) - Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. - GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler. - GHGhostBehaviour should define #currentMetaLevel to specify set of messages which should not be intercepted. Such meta messages will be executed under ghost instance by subclass of GHMetaMessages.
In previous version there was dictionary which maps meta message selector to implementation selector. It was not suitable. Now meta messages should be directly implemented on particular GHMetaMessages subclass and all it methods are considered meta.
So GhostBehaviour should return instance of GHMetaLevel with meta messages implementation class:
- GHMetaLevel with: GHEmptyMetaMessages "when all possible messages should intercepted" - GHMetaLevel with: GHStandartMetaMessages "when tools specific messages should not be intercepted"
For example standard meta messages implements #inspect:
GHStandartMetaMessages>>inspect
"Create and schedule an Inspector in which the user can examine the receiver's variables."
^ Smalltalk tools inspector inspect: *ghost*
- Traits for methods explicitly defined on ghosts: TMinimalProxy, TNotNilProxy, TIdentifiedProxy (with #=, #hash, #class). Concrete proxies can add this traits to itself independently from meta level. For example traits supply convenient methods to retrieve ghost information in polymorphic way with objects: - ghost isGhost - ghost ghostClass "returns actual class of receiver" - ghost ghostPrintString "returns string which represents ghost from meta level point of view"
This traits are suitable and they provide some kind of optimisation for proxies (methods from traits are executed directly instead of complex meta messages mechanizm). But maybe they are superfluous. For example they can't be reused for class proxies which substitute real object classes (to intercept all instance messages).
- GHClassGhost able to replace class of real objects. It implements cannotInterpret: trick to intercept all instance messages. Subclasses should define two behaviours: #ghostBehaviour (as any other ghost) and #instancesBehaviour which will process instance messages. In previous version it was different message to same #ghostBehaviour. - New kind of proxies: - GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim class. So in case when virus is created with standard meta level tools will not differ him from health object. There are special messages which allow ask object about viruses: - infectedObject isInfectedByVirus - infectedObject virus - infectedObject recoverFromVirus
- GHLearningObject. It is suitable proxy which retrieves all unknown methods from teacher class. Thank's Stephan for this idea.
This kind of proxy allows me easily find required set of messages to support inspectors and debuggers. You can create instance of learning object by:
GHLearningObject withTeacher: Object.
And any operation with it will fill studiedMessages dictionary. In my case I opened GTInspector on it and got all messages which was needed for him.
- Ghosts works correctly with latest Pharo 5 tools (basic inspector, GTInspector, SpecDebugger, GTDebugger). Required methods for tools are extracted to 'Ghost-GTSupport' package. - Repackaging: - Ghost-ObjectProxies. It contains all core classes and abstract GHObjectGhost which is based on DNU - Ghost-ClassProxies. It contains code for proxy which can substitute class of real object. GHClassGhost implements cannotInterpret: trick to intercept all instance messages. And it implement support for debugging such methods. - Ghost-LearningObject - Ghost-ObjectVirus - Ghost-GTSupport - test packages - All code moved to Pharo repository http://smalltalkhub.com/#!/~Pharo/Ghost (in includes packages from CAR repo too)
You can load new version by:
Gofer it smalltalkhubUser: 'Pharo' project: 'Ghost'; configurationOf: 'Ghost'; loadStable
I use it now in Seamless and Mocketry.
2016-03-24 19:15 GMT+01:00 phil@highoctane.be <phil@highoctane.be>:
Awesome. Things are looking good.
Now, just have to find time to use all of this :-)
I just should say that I am not succeed to provide really safe ghosts. If you will try to implement new kind of proxy (on top of Ghost) it is possible to hang image. Problem that when you make some mistake in implementation it usually lead to infinite recursion and interrupt usually not helps because opened debugger produces new messages to ghost which produces another recursion due to original errors. And errors are not only exceptions but some unexpected messages to proxies. For example if you will use Set to implement proxy behaviour (for some reason) it will send #= and #hash to proxy when you will try to add it. There are tools now to minimize such cases. For example standart meta level will not intercept messages from debugger. But as soon as you start experiment with empty meta level you will get such problems. This week Guille Polito start to use Ghost for new proxies and he was not happy due to this kind of problems. Maybe together we will find some solution how to make ghosts safe.
On Thu, Mar 24, 2016 at 4:33 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2016-03-24 19:15 GMT+01:00 phil@highoctane.be <phil@highoctane.be>:
Awesome. Things are looking good.
Now, just have to find time to use all of this :-)
I just should say that I am not succeed to provide really safe ghosts. If you will try to implement new kind of proxy (on top of Ghost) it is possible to hang image. Problem that when you make some mistake in implementation it usually lead to infinite recursion and interrupt usually not helps because opened debugger produces new messages to ghost which produces another recursion due to original errors. And errors are not only exceptions but some unexpected messages to proxies. For example if you will use Set to implement proxy behaviour (for some reason) it will send #= and #hash to proxy when you will try to add it.
Exactly. That's why Marea had to extend Fuel because otherwise, when I was serializing a graph that contained proxies, the Fuel message sends to the proxy would be intercepted and cause the swap in! hahahah. Therefore, in Marea I extend Fuel to use a custom dictionary and a custom cluster for proxies :) Ohh that's another interesting example that would be nice to be added to this new Ghost.
There are tools now to minimize such cases. For example standart meta level will not intercept messages from debugger. But as soon as you start experiment with empty meta level you will get such problems. This week Guille Polito start to use Ghost for new proxies and he was not happy due to this kind of problems. Maybe together we will find some solution how to make ghosts safe.
-- Mariano http://marianopeck.wordpress.com
On Thu, Mar 24, 2016 at 1:48 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
Hello.
I finished new version of Ghost:
That's very nice to hear!! I love to see someone took it and improve it :)
- DNU approach for basic proxies instead of #cannotInterpret: trick (trick used only for class proxies)
Excellent. Yes, I remember the discussion we had weeks ago.
- - Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. - GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler. - GHGhostBehaviour should define #currentMetaLevel to specify set of messages which should not be intercepted. Such meta messages will be executed under ghost instance by subclass of GHMetaMessages.
In previous version there was dictionary which maps meta message selector to implementation selector. It was not suitable. Now meta messages should be directly implemented on particular GHMetaMessages subclass and all it methods are considered meta.
So GhostBehaviour should return instance of GHMetaLevel with meta messages implementation class:
- GHMetaLevel with: GHEmptyMetaMessages "when all possible messages should intercepted" - GHMetaLevel with: GHStandartMetaMessages "when tools specific messages should not be intercepted"
For example standard meta messages implements #inspect:
GHStandartMetaMessages>>inspect
"Create and schedule an Inspector in which the user can examine the receiver's variables."
^ Smalltalk tools inspector inspect: *ghost*
Nice. Yes, this is much better than my original dictionary-based solution
- Traits for methods explicitly defined on ghosts: TMinimalProxy, TNotNilProxy, TIdentifiedProxy (with #=, #hash, #class). Concrete proxies can add this traits to itself independently from meta level. For example traits supply convenient methods to retrieve ghost information in polymorphic way with objects: - ghost isGhost - ghost ghostClass "returns actual class of receiver" - ghost ghostPrintString "returns string which represents ghost from meta level point of view"
This traits are suitable and they provide some kind of optimisation for proxies (methods from traits are executed directly instead of complex meta messages mechanizm). But maybe they are superfluous. For example they can't be reused for class proxies which substitute real object classes (to intercept all instance messages).
Good idea as well. Just as yet another useful example of this, I recommend watching the proxies I defined for Marea as you will have interesting proxies for classes and metaclasses. Basically, I defined quite some methods in those proxies so that to avoid intercepting and faulting my objects. See Marea code and watch for it's proxies! Let me know if you found the methods I am talking about.
- GHClassGhost able to replace class of real objects. It implements cannotInterpret: trick to intercept all instance messages. Subclasses should define two behaviours: #ghostBehaviour (as any other ghost) and #instancesBehaviour which will process instance messages. In previous version it was different message to same #ghostBehaviour. - New kind of proxies: - GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim class. So in case when virus is created with standard meta level tools will not differ him from health object. There are special messages which allow ask object about viruses: - infectedObject isInfectedByVirus - infectedObject virus - infectedObject recoverFromVirus
Sorry I did not get this one.
- GHLearningObject. It is suitable proxy which retrieves all unknown methods from teacher class. Thank's Stephan for this idea.
This kind of proxy allows me easily find required set of messages to support inspectors and debuggers. You can create instance of learning object by:
GHLearningObject withTeacher: Object.
And any operation with it will fill studiedMessages dictionary. In my case I opened GTInspector on it and got all messages which was needed for him.
Great idea too. I had to come with the set of mapped selectors (the dictionary) by poor man human try and error hahaha.
- Ghosts works correctly with latest Pharo 5 tools (basic inspector, GTInspector, SpecDebugger, GTDebugger). Required methods for tools are extracted to 'Ghost-GTSupport' package. - Repackaging: - Ghost-ObjectProxies. It contains all core classes and abstract GHObjectGhost which is based on DNU - Ghost-ClassProxies. It contains code for proxy which can substitute class of real object. GHClassGhost implements cannotInterpret: trick to intercept all instance messages. And it implement support for debugging such methods. - Ghost-LearningObject - Ghost-ObjectVirus - Ghost-GTSupport - test packages - All code moved to Pharo repository http://smalltalkhub.com/#!/~Pharo/Ghost (in includes packages from CAR repo too)
Excellent. Thanks Denis for pushing Ghost further! -- Mariano http://marianopeck.wordpress.com
Hi. Thank's for kind words. 2016-03-24 19:22 GMT+01:00 Mariano Martinez Peck <marianopeck@gmail.com>:
- GHClassGhost able to replace class of real objects. It implements cannotInterpret: trick to intercept all instance messages. Subclasses should define two behaviours: #ghostBehaviour (as any other ghost) and #instancesBehaviour which will process instance messages. In previous version it was different message to same #ghostBehaviour.
In your original version you implemented #cannotInterpert: for instance messages such way: proxy proxyHandler *handleInterceptionToInstance:* interception. And proxy handler was responsible for two messages: #handleInterceptionToInstance: and #handleInterception:. In my version I ask proxy for different kind of handler (ghostBehaviour): GHObjectGhost>>doesNotUnderstand: aMessage self *ghostBehaviour* intercept: aMessage to: self GHInstanceMessagesInterceptor>>cannotInterpret: aMessage "some logic to find ghostClass" ghostClass *instancesBehaviour* intercept: aMessage to: self
- New kind of proxies: - GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim class. So in case when virus is created with standard meta level tools will not differ him from health object. There are special messages which allow ask object about viruses: - infectedObject isInfectedByVirus - infectedObject virus - infectedObject recoverFromVirus
Sorry I did not get this one.
Good example where I use viruses is stubbing real objects in Mocketry. I will announce it soon. You can do this: rect := 0@0 corner: 2@3 rect stub area willReturn: 1000. rect area "=> 1000". rect origin "=> 0@0".
From any tool you will see normal rectangle. Nothing special. But in reality it is infected by virus which delegate all messages to "Mocketry machinery". And you can detect it by:
rect isInfectedByVirus "=> true" And you can heal infected object: rect recoverFromVirus. "or virus heal: infectedObject" rect isInfectedByVirus "=> false"
On Thu, Mar 24, 2016 at 4:02 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
Hi. Thank's for kind words.
2016-03-24 19:22 GMT+01:00 Mariano Martinez Peck <marianopeck@gmail.com>:
- GHClassGhost able to replace class of real objects. It implements cannotInterpret: trick to intercept all instance messages. Subclasses should define two behaviours: #ghostBehaviour (as any other ghost) and #instancesBehaviour which will process instance messages. In previous version it was different message to same #ghostBehaviour.
In your original version you implemented #cannotInterpert: for instance messages such way: proxy proxyHandler *handleInterceptionToInstance:* interception. And proxy handler was responsible for two messages: #handleInterceptionToInstance: and #handleInterception:. In my version I ask proxy for different kind of handler (ghostBehaviour):
GHObjectGhost>>doesNotUnderstand: aMessage
self *ghostBehaviour* intercept: aMessage to: self
GHInstanceMessagesInterceptor>>cannotInterpret: aMessage
"some logic to find ghostClass"
ghostClass *instancesBehaviour* intercept: aMessage to: self
OK, that's good. I like it.
- New kind of proxies: - GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim class. So in case when virus is created with standard meta level tools will not differ him from health object. There are special messages which allow ask object about viruses: - infectedObject isInfectedByVirus - infectedObject virus - infectedObject recoverFromVirus
Sorry I did not get this one.
Good example where I use viruses is stubbing real objects in Mocketry. I will announce it soon. You can do this:
rect := 0@0 corner: 2@3 rect stub area willReturn: 1000.
rect area "=> 1000". rect origin "=> 0@0".
OK..I should take a look to the code...but...it looks to me that stub the only thing it does is to create the proxy and then the #become: ?? -- Mariano http://marianopeck.wordpress.com
2016-03-25 1:34 GMT+01:00 Mariano Martinez Peck <marianopeck@gmail.com>:
Good example where I use viruses is stubbing real objects in Mocketry. I
will announce it soon. You can do this:
rect := 0@0 corner: 2@3 rect stub area willReturn: 1000.
rect area "=> 1000". rect origin "=> 0@0".
OK..I should take a look to the code...but...it looks to me that stub the only thing it does is to create the proxy and then the #become: ??
No. Stub should intercept all self-sends. Classic proxy can't do this. Better example to show self-send stubbing: rect := 0@0 corner: 2@3 rect stub width willReturn: 1000. rect area "=> 3000" (area is width and height multiplication).
2016-03-24 19:22 GMT+01:00 Mariano Martinez Peck <marianopeck@gmail.com>:
Good idea as well. Just as yet another useful example of this, I recommend watching the proxies I defined for Marea as you will have interesting proxies for classes and metaclasses. Basically, I defined quite some methods in those proxies so that to avoid intercepting and faulting my objects. See Marea code and watch for it's proxies! Let me know if you found the methods I am talking about.
And where is code? Of course I want to look
On Thu, Mar 24, 2016 at 4:52 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2016-03-24 19:22 GMT+01:00 Mariano Martinez Peck <marianopeck@gmail.com>:
Good idea as well. Just as yet another useful example of this, I recommend watching the proxies I defined for Marea as you will have interesting proxies for classes and metaclasses. Basically, I defined quite some methods in those proxies so that to avoid intercepting and faulting my objects. See Marea code and watch for it's proxies! Let me know if you found the methods I am talking about.
And where is code? Of course I want to look
The code is in http://ss3.gemstone.com/ss/Marea BTW..note that last time I tried Marea was in Pharo 1.4 so.. not sure if it would load now. I have a one-click in either case that you can find here: https://www.dropbox.com/sh/xp8jzyypmz0898j/AACRdHno6V7UfhaJ1ofTPPXva?dl=0 And what you are looking is in category 'Marea-Proxies'. See for example MARClassProxy or MARMetaclassProxy as the examples were I added messages to the proxies to avoid being intercepted. Those methods allowed me the reduce the unncessary "swap in" when I had swapped out classes and instances and suddently a simple #do: over behaviors swapped everything in. In Marea you will find the IMPORTANT work for which I used Ghost approach. Cheers, -- Mariano http://marianopeck.wordpress.com
Le 24/3/16 17:48, Denis Kudriashov a écrit :
Hello.
I finished new version of Ghost:
* DNU approach for basic proxies instead of #cannotInterpret: trick (trick used only for class proxies)
Does it mean that we cannot proxy classes?
* Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. * GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler. * GHGhostBehaviour should define #currentMetaLevel to specify set of messages which should not be intercepted. Such meta messages will be executed under ghost instance by subclass of GHMetaMessages.
In previous version there was dictionary which maps meta message selector to implementation selector. It was not suitable. Now meta messages should be directly implemented on particular GHMetaMessages subclass and all it methods are considered meta.
So GhostBehaviour should return instance of GHMetaLevel with meta messages implementation class:
o GHMetaLevel with: GHEmptyMetaMessages "when all possible messages should intercepted" o GHMetaLevel with: GHStandartMetaMessages "when tools specific messages should not be intercepted"
For example standard meta messages implements #inspect:
GHStandartMetaMessages>>inspect
"Create and schedule an Inspector in which the user can examine the receiver's variables."
^ Smalltalk tools inspector inspect: *ghost*
* Traits for methods explicitly defined on ghosts: TMinimalProxy, TNotNilProxy, TIdentifiedProxy (with #=, #hash, #class). Concrete proxies can add this traits to itself independently from meta level. For example traits supply convenient methods to retrieve ghost information in polymorphic way with objects: o ghost isGhost o ghost ghostClass "returns actual class of receiver" o ghost ghostPrintString "returns string which represents ghost from meta level point of view"
This traits are suitable and they provide some kind of optimisation for proxies (methods from traits are executed directly instead of complex meta messages mechanizm). But maybe they are superfluous. For example they can't be reused for class proxies which substitute real object classes (to intercept all instance messages).
* GHClassGhost able to replace class of real objects. It implements cannotInterpret: trick to intercept all instance messages. Subclasses should define two behaviours: #ghostBehaviour (as any other ghost) and #instancesBehaviour which will process instance messages. In previous version it was different message to same #ghostBehaviour. * New kind of proxies: o GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim class. So in case when virus is created with standard meta level tools will not differ him from health object. There are special messages which allow ask object about viruses: + infectedObject isInfectedByVirus + infectedObject virus + infectedObject recoverFromVirus
o GHLearningObject. It is suitable proxy which retrieves all unknown methods from teacher class. Thank's Stephan for this idea.
This kind of proxy allows me easily find required set of messages to support inspectors and debuggers. You can create instance of learning object by:
GHLearningObject withTeacher: Object.
And any operation with it will fill studiedMessages dictionary. In my case I opened GTInspector on it and got all messages which was needed for him.
* Ghosts works correctly with latest Pharo 5 tools (basic inspector, GTInspector, SpecDebugger, GTDebugger). Required methods for tools are extracted to 'Ghost-GTSupport' package. * Repackaging: o Ghost-ObjectProxies. It contains all core classes and abstract GHObjectGhost which is based on DNU o Ghost-ClassProxies. It contains code for proxy which can substitute class of real object. GHClassGhost implements cannotInterpret: trick to intercept all instance messages. And it implement support for debugging such methods. o Ghost-LearningObject o Ghost-ObjectVirus o Ghost-GTSupport o test packages * All code moved to Pharo repository http://smalltalkhub.com/#!/~Pharo/Ghost <http://smalltalkhub.com/#%21/%7EPharo/Ghost> (in includes packages from CAR repo too)
You can load new version by:
Gofer it smalltalkhubUser: 'Pharo' project: 'Ghost'; configurationOf: 'Ghost'; loadStable
I use it now in Seamless and Mocketry.
Le 24/3/16 17:48, Denis Kudriashov a écrit :
Hello.
I finished new version of Ghost:
* DNU approach for basic proxies instead of #cannotInterpret: trick (trick used only for class proxies) * Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. * GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler. * GHGhostBehaviour should define #currentMetaLevel to specify set of messages which should not be intercepted. Such meta messages will be executed under ghost instance by subclass of GHMetaMessages.
In previous version there was dictionary which maps meta message selector to implementation selector. It was not suitable. Now meta messages should be directly implemented on particular GHMetaMessages subclass and all it methods are considered meta.
So GhostBehaviour should return instance of GHMetaLevel with meta messages implementation class:
Do you mean that you use subclasses to register selectors that will not be trapped? Why is is better than a collection on the object?
o GHMetaLevel with: GHEmptyMetaMessages "when all possible messages should intercepted" o GHMetaLevel with: GHStandartMetaMessages "when tools specific messages should not be intercepted"
For example standard meta messages implements #inspect:
Pay attention Standard and no Standart
GHStandartMetaMessages>>inspect
"Create and schedule an Inspector in which the user can examine the receiver's variables."
^ Smalltalk tools inspector inspect: *ghost*
* Traits for methods explicitly defined on ghosts: TMinimalProxy, TNotNilProxy, TIdentifiedProxy (with #=, #hash, #class). Concrete proxies can add this traits to itself independently from meta level. For example traits supply convenient methods to retrieve ghost information in polymorphic way with objects: o ghost isGhost o ghost ghostClass "returns actual class of receiver"
when I read ghostClass I expect getting the class implementing the proxy not the proxied class. So I'm confused.
o ghost ghostPrintString "returns string which represents ghost from meta level point of view"
This traits are suitable and they provide some kind of optimisation for proxies (methods from traits are executed directly instead of complex meta messages mechanizm). But maybe they are superfluous. For example they can't be reused for class proxies which substitute real object classes (to intercept all instance messages).
* GHClassGhost able to replace class of real objects. It implements cannotInterpret: trick to intercept all instance messages. Subclasses should define two behaviours: #ghostBehaviour (as any other ghost) and #instancesBehaviour which will process instance messages. In previous version it was different message to same #ghostBehaviour. * New kind of proxies: o GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim class. So in case when virus is created with standard meta level tools will not differ him from health object. There are special messages which allow ask object about viruses: + infectedObject isInfectedByVirus + infectedObject virus + infectedObject recoverFromVirus
I could not understand what is a Virus.
o GHLearningObject. It is suitable proxy which retrieves all unknown methods from teacher class. Thank's Stephan for this idea.
This kind of proxy allows me easily find required set of messages to support inspectors and debuggers. You can create instance of learning object by:
GHLearningObject withTeacher: Object.
And any operation with it will fill studiedMessages dictionary. In my case I opened GTInspector on it and got all messages which was needed for him.
:)
* Ghosts works correctly with latest Pharo 5 tools (basic inspector, GTInspector, SpecDebugger, GTDebugger). Required methods for tools are extracted to 'Ghost-GTSupport' package. * Repackaging: o Ghost-ObjectProxies. It contains all core classes and abstract GHObjectGhost which is based on DNU o Ghost-ClassProxies. It contains code for proxy which can substitute class of real object. GHClassGhost implements cannotInterpret: trick to intercept all instance messages. And it implement support for debugging such methods. o Ghost-LearningObject o Ghost-ObjectVirus o Ghost-GTSupport o test packages * All code moved to Pharo repository http://smalltalkhub.com/#!/~Pharo/Ghost <http://smalltalkhub.com/#%21/%7EPharo/Ghost> (in includes packages from CAR repo too)
Denis it would be good to have some examples described.
You can load new version by:
Gofer it smalltalkhubUser: 'Pharo' project: 'Ghost'; configurationOf: 'Ghost'; loadStable
I use it now in Seamless and Mocketry.
On 24 March 2016 at 20:38, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2016-03-24 20:27 GMT+01:00 stepharo <stepharo@free.fr>:
Pay attention Standard and no Standart
So what the right word? Standart exists in my english dictionary
Standard with a D is correct; only version found in my copy of the Oxford English Dictionary. Standart with a T is a proper name, according to wikipedia https://en.wikipedia.org/wiki/Standart -- Damien Pollet type less, do more [ | ] http://people.untyped.org/damien.pollet
2016-03-24 23:26 GMT+01:00 Damien Pollet <damien.pollet@gmail.com>:
Standard with a D is correct; only version found in my copy of the Oxford English Dictionary.
Standart with a T is a proper name, according to wikipedia https://en.wikipedia.org/wiki/Standart
Interesting. I will rename it
2016-03-24 20:27 GMT+01:00 stepharo <stepharo@free.fr>:
Do you mean that you use subclasses to register selectors that will not be trapped?
Why is is better than a collection on the object?
I not understand your question. For example you want to make message #asString meta. You can implement it directly in class GHStandartMetaMessages: GHStandartMetaMessages>>asString "here there is instance variable *ghost *which you can use for implementation" ^'string presentation for ghost' Now if you will define your proxy with standart meta level #asString will be not intercepted and instead GHStandartMetaMessages>>asString will be executed with ghost. In previous version you would add #asString to special map: initializeMetaLevel "many many other mappings here and new one" notInterceptedMessages at: #asString put: #handleAsStringFor:
2016-03-24 20:27 GMT+01:00 stepharo <stepharo@free.fr>:
- ghost ghostClass "returns actual class of receiver"
when I read ghostClass I expect getting the class implementing the proxy not the proxied class. So I'm confused.
Now I am confused too :)) ghost ghostClass "=> anObjectGhost (or subclass)"
I upload new version 2.1 which not mentions word "proxy" anymore. And I publish little example here http://dionisiydk.blogspot.fr/2016/03/new-version-of-ghost-is-out.html 2016-03-27 21:03 GMT+02:00 Denis Kudriashov <dionisiydk@gmail.com>:
2016-03-24 20:27 GMT+01:00 stepharo <stepharo@free.fr>:
- ghost ghostClass "returns actual class of receiver"
when I read ghostClass I expect getting the class implementing the proxy not the proxied class. So I'm confused.
Now I am confused too :))
ghost ghostClass "=> anObjectGhost (or subclass)"
I publish little example of ObjectVirus http://dionisiydk.blogspot.fr/2016/04/playing-with-objectvirus.html 2016-03-29 16:59 GMT+02:00 Denis Kudriashov <dionisiydk@gmail.com>:
I upload new version 2.1 which not mentions word "proxy" anymore.
And I publish little example here http://dionisiydk.blogspot.fr/2016/03/new-version-of-ghost-is-out.html
2016-03-27 21:03 GMT+02:00 Denis Kudriashov <dionisiydk@gmail.com>:
2016-03-24 20:27 GMT+01:00 stepharo <stepharo@free.fr>:
- ghost ghostClass "returns actual class of receiver"
when I read ghostClass I expect getting the class implementing the proxy not the proxied class. So I'm confused.
Now I am confused too :))
ghost ghostClass "=> anObjectGhost (or subclass)"
Good job Denis!
Le 24 mars 2016 à 17:48, Denis Kudriashov <dionisiydk@gmail.com> a écrit :
Hello.
I finished new version of Ghost: Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler.
Why did you rename these classes? I find the new names obscure and they do not provide a clue of what is the purpose of the class. Old names were clear and easily understandable.
New kind of proxies: GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim Same remark here. The name is fun but it does not give any clue on the purpose of the class. Why not use GHMessageInterceptor?
Sorry to bother you but names are really important. Christophe
On Fri, Mar 25, 2016 at 5:47 AM, Christophe Demarey < christophe.demarey@inria.fr> wrote:
Good job Denis!
Le 24 mars 2016 à 17:48, Denis Kudriashov <dionisiydk@gmail.com> a écrit :
Hello.
I finished new version of Ghost:
- Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. - GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler.
Why did you rename these classes? I find the new names obscure and they do not provide a clue of what is the purpose of the class. Old names were clear and easily understandable.
I agree here. I originally called the tool Ghost mostly because I wanted TRANSPARENT proxies for all kind of objects (included classes, methods, etc), and LIGHTWEIGHT. So...I thought that Ghost were transparent and lightweight hahahaha. But... one thing is the project name and the other is class names. Here I agree with Christophe that I prefer the old names. Same as for the virus stuff. I would not go that deep into the metaphor. -- Mariano http://marianopeck.wordpress.com
2016-03-25 13:26 GMT+01:00 Mariano Martinez Peck <marianopeck@gmail.com>:
I agree here. I originally called the tool Ghost mostly because I wanted TRANSPARENT proxies for all kind of objects (included classes, methods, etc), and LIGHTWEIGHT. So...I thought that Ghost were transparent and lightweight hahahaha.
But I realised real value of this metaphor (not just lightness). I answer to Christophe
Hi 2016-03-25 9:47 GMT+01:00 Christophe Demarey <christophe.demarey@inria.fr>:
- Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. - GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler.
Why did you rename these classes? I find the new names obscure and they do not provide a clue of what is the purpose of the class. Old names were clear and easily understandable.
Nice you ask. It can raise interesting discussion. In previous version we have three classes to support basic object proxy: GHInterceptionDelegator GHProxyTrap GHAbstractProxy And now due to DNU approach it just one: GHObjectGhost And I guess you would call it GHObjectProxy or GHAbstractProxy. Lets look at wikipedia:
A *proxy*, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes
So proxy is supposed to substitute some other object. But in many cases we not have other object. In many cases we construct special kind of objects which perform messages in not smalltalk way. For example imaging that we want to implement javascript prototypes (there was related post https://clementbera.wordpress.com/2016/02/17/mind-twister-toying-with-object...). Prototype is definitely not kind of proxy. Or think about Mock object. It is not proxy too. So generally Ghost is not about proxies. It is exactly about supernatural objects. With Ghost we construct special objects which behave in not natural smalltalk way. And in that perspective classic proxy is most primitive example of it. It just delegates all messages to another object (with little bit of logic). Maybe you would suggest another name: GHInterceptionDelegator (what the name for GHGhostClass in that case?). But why we not call Object same way too (InterceptionDelegator)? Natural smalltalk objects just delegate message processing to methods from class methodDictionary (which is hidden by VM). So for me ObjectGhost reflects perfectly real intention of it. It is base class to construct unnatural smalltalk objects. And ClassGhost is unnatural object which can play role of natural object classes. Now lets look at ProxyHandler vs GhostBehaviour. ProxyHandler play role of Behavior (Class) but for proxies. It defines how proxies will handle messages. But why we not call smalltalk Behaviour as ObjectHandler? I hope now you see logic behind my names and ghost metaphor. Ghost models special objects with similar terms from natural objects: Object -> ObjectGhost and Behavior -> GhostBehaviour. I changed title of Ghost project to: Ghost is framework to implement unnatural smalltalk objects like proxies and prototypes.,
- New kind of proxies: - GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim
Same remark here. The name is fun but it does not give any clue on the purpose of the class. Why not use GHMessageInterceptor?
And following such approach we will have GHInterceptionDelegator (for objects) and GHMessageInterceptor (for classes). Is it good? I will describe virus more detailed soon. But maybe you remember there was very old advice from famous books: don't create classes which ends with -ER or -OR. (I not found original source but google shows many followers http://www.yegor256.com/2015/03/09/objects-end-with-er.html http://objology.blogspot.fr/2011/09/one-of-best-bits-of-programming-advice.h... )
Sorry to bother you but names are really important.
Exactly!!!
2016-03-25 14:54 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
Sorry to bother you but names are really important.
Exactly!!!
Forgot to say. When I see words in class names like Abstract, Handler, Delegator... I remember many "good" years with java. Please lets make names better.
Le 25 mars 2016 à 14:54, Denis Kudriashov <dionisiydk@gmail.com> a écrit :
Hi
2016-03-25 9:47 GMT+01:00 Christophe Demarey <christophe.demarey@inria.fr <mailto:christophe.demarey@inria.fr>>:
Abstract proxy classes uses Ghost name instead of Proxy: there are GHObjectGhost and GHClassGhost. GHProxyHandler renamed to GHGhostBehaviour. Concrete ghosts should implement #ghostBehaviour instead of #proxyHandler.
Why did you rename these classes? I find the new names obscure and they do not provide a clue of what is the purpose of the class. Old names were clear and easily understandable.
Nice you ask. It can raise interesting discussion.
In previous version we have three classes to support basic object proxy: GHInterceptionDelegator GHProxyTrap GHAbstractProxy And now due to DNU approach it just one: GHObjectGhost
And I guess you would call it GHObjectProxy or GHAbstractProxy. Lets look at wikipedia:
A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes
So proxy is supposed to substitute some other object. But in many cases we not have other object. In many cases we construct special kind of objects which perform messages in not smalltalk way. For example imaging that we want to implement javascript prototypes (there was related post https://clementbera.wordpress.com/2016/02/17/mind-twister-toying-with-object... <https://clementbera.wordpress.com/2016/02/17/mind-twister-toying-with-object...>). Prototype is definitely not kind of proxy. Or think about Mock object. It is not proxy too. So generally Ghost is not about proxies. It is exactly about supernatural objects. With Ghost we construct special objects which behave in not natural smalltalk way.
so is most magic than surnatural ;)
And in that perspective classic proxy is most primitive example of it. It just delegates all messages to another object (with little bit of logic).
Maybe you would suggest another name: GHInterceptionDelegator (what the name for GHGhostClass in that case?). But why we not call Object same way too (InterceptionDelegator)? Natural smalltalk objects just delegate message processing to methods from class methodDictionary (which is hidden by VM).
So for me ObjectGhost reflects perfectly real intention of it. It is base class to construct unnatural smalltalk objects. And ClassGhost is unnatural object which can play role of natural object classes.
Now lets look at ProxyHandler vs GhostBehaviour. ProxyHandler play role of Behavior (Class) but for proxies. It defines how proxies will handle messages. But why we not call smalltalk Behaviour as ObjectHandler? I hope now you see logic behind my names and ghost metaphor. Ghost models special objects with similar terms from natural objects: Object -> ObjectGhost and Behavior -> GhostBehaviour.
Thanks for the answer. I now see more the rationale behind your naming but it is not obvious at a first sight. If not there, please explain it in documentation, comments.
I changed title of Ghost project to: Ghost is framework to implement unnatural smalltalk objects like proxies and prototypes.,
New kind of proxies: GHObjectVirus. It is special kind of GHClassProxy. It infects real object to intercept it messages. From meta level infected object looks like healthy object which means that meta messages are executed by infected object itself. As class virus looks like real victim
Same remark here. The name is fun but it does not give any clue on the purpose of the class. Why not use GHMessageInterceptor?
And following such approach we will have GHInterceptionDelegator (for objects) and GHMessageInterceptor (for classes). Is it good? I will describe virus more detailed soon. But maybe you remember there was very old advice from famous books: don't create classes which ends with -ER or -OR. (I not found original source but google shows many followers http://www.yegor256.com/2015/03/09/objects-end-with-er.html <http://www.yegor256.com/2015/03/09/objects-end-with-er.html> http://objology.blogspot.fr/2011/09/one-of-best-bits-of-programming-advice.h... <http://objology.blogspot.fr/2011/09/one-of-best-bits-of-programming-advice.h...>)
you have it in âSmalltalk best practicesâ for sure Thanks for the detailed answer Denis, Christophe
participants (6)
-
Christophe Demarey -
Damien Pollet -
Denis Kudriashov -
Mariano Martinez Peck -
phil@highoctane.be -
stepharo