Unexpected ProtoObject behaviour

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

Unexpected ProtoObject behaviour

Mikael Svane
I have a number of ProtoObject subclasses in different packages that add
behaviour to a Model subclass by forwarding failed messages using
#doesNotUnderstand:. I have choosen to do it this way, because I cannot add
the added behaviour by subclassing the model, which has other subclasses
that also need the new behaviour, which requires the use of additional
instance variables and therefore cannot be implemented using loose methods.

The unexpected behaviour that I will describe below is seen when one
ProtoObject wraps another one that then wraps the Model. This is an example
package that I have created (example code of the is found below the
package):

--------Package starts---------

| package |
package := Package name: 'ProtoFailure'.
package paxVersion: 0;
 basicComment: ''.


package classNames
 add: #BottomProtoObject;
 add: #ModelForProtoObjects;
 add: #TopProtoObject;
 yourself.

package binaryGlobalNames: (Set new
 yourself).

package globalAliases: (Set new
 yourself).

package allResourceNames: (Set new
 yourself).

package setPrerequisites: (IdentitySet new
 add: '..\Object Arts\Dolphin\Base\Dolphin';
 yourself).

package!

"Class Definitions"!

Model subclass: #ModelForProtoObjects
 instanceVariableNames: ''
 classVariableNames: ''
 poolDictionaries: ''
 classInstanceVariableNames: ''!
ProtoObject subclass: #BottomProtoObject
 instanceVariableNames: 'model'
 classVariableNames: ''
 poolDictionaries: ''
 classInstanceVariableNames: ''!
ProtoObject subclass: #TopProtoObject
 instanceVariableNames: 'model'
 classVariableNames: ''
 poolDictionaries: ''
 classInstanceVariableNames: ''!

"Global Aliases"!


"Loose Methods"!

"End of package definition"!

"Source Globals"!

"Classes"!

ModelForProtoObjects guid: (GUID fromString:
'{305F4BE9-47BB-4E4C-8DDF-8F8F9968B4EE}')!
ModelForProtoObjects comment: ''!
!ModelForProtoObjects categoriesForClass!MVP-Models! !
!ModelForProtoObjects methodsFor!

modelBehaviour

 Transcript show: 'ModelForProtoObjects'; cr! !
!ModelForProtoObjects categoriesFor: #modelBehaviour!public! !

BottomProtoObject guid: (GUID fromString:
'{56C13393-722E-4A98-A4EF-CF2368608DBD}')!
BottomProtoObject comment: ''!
!BottomProtoObject categoriesForClass!System-Support! !
!BottomProtoObject methodsFor!

bottomBehaviour

 Transcript show: 'BottomProtoObject'; cr!

doesNotUnderstand: failedMessage

 ^ failedMessage forwardTo: model!

model
 ^model!

model: anObject
 model := anObject! !
!BottomProtoObject categoriesFor: #bottomBehaviour!public! !
!BottomProtoObject categoriesFor: #doesNotUnderstand:!public! !
!BottomProtoObject categoriesFor: #model!accessing!private! !
!BottomProtoObject categoriesFor: #model:!accessing!private! !

TopProtoObject guid: (GUID fromString:
'{B15680F9-5017-4A17-905B-4A567E6B53B0}')!
TopProtoObject comment: ''!
!TopProtoObject categoriesForClass!System-Support! !
!TopProtoObject methodsFor!

doesNotUnderstand: failedMessage

 ^ failedMessage forwardTo: model!

model
 ^model!

model: anObject
 model := anObject!

topBehaviour

 Transcript show: 'TopProtoObject'; cr! !
!TopProtoObject categoriesFor: #doesNotUnderstand:!public! !
!TopProtoObject categoriesFor: #model!accessing!private! !
!TopProtoObject categoriesFor: #model:!accessing!private! !
!TopProtoObject categoriesFor: #topBehaviour!public! !

"Binary Globals"!

"Resources"!

--------Package ends---------

--------Example code starts--------

After installing the above package, try the following in a workspace:

model := ModelForProtoObjects new.
model modelBehaviour.  "this prints text in the Transcript."

bottom := BottomProtoObject new.
bottom model: model.
bottom modelBehaviour.   "this works. The failed message is forwarded to the
model and text is shown."
bottom bottomBehaviour. "this also works. The message is performed by the
BottomProtoObject and text is shown."

top := TopProtoObject new.
top model: bottom.   "we now wrap the BottomProtoObject in order to add even
more behaviour."

top modelBehaviour.  "this works. The failed message is forwarded to the
BottomProtoObject which forwards it to the model and text is shown."

top topBehaviour. "this also works. The message is performed by the
TopProtoObject and text is shown."

top bottomBehaviour.   "this does _not_ work. By stepping through the code
it is obvious that the failed message is correctly forwarded to the
BottomProtoObject which then claims that it doesn't understand the message,
despite the fact that the message is implemented there. It is therefore
forwarded to the ModelForProtoObjects, which of course doesn't understand
it."

top model bottomBehaviour.    "however this works."

-----Example code ends----

I didn't expect this behaviour and it took some time to figure out what was
happening. What I wonder is if this is a bug or if the ProtoObjects cannot
be used this way (and in that case, why not?).

Best regards,

Mikael Svane


Reply | Threaded
Open this post in threaded view
|

Re: Unexpected ProtoObject behaviour

Bill Schwab-2
Mikael,

I think your problem is that the proto objects do not understand
#perform:withArguments:; if you steal Object's code for it, the troublesome
case should start to work.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Unexpected ProtoObject behaviour

Mikael Svane
Bill,

Thanks! I had previously copied #perform:withArguments: to ProtoObject, but
forgotten to add it to the loose methods of one of the packages. When
restarting Dolphin (I often don't save the image. I use packages instead)
the method of course was gone, which resulted in the strange behaviour.

Best regards,

Mikael Svane



"Bill Schwab" <[hidden email]> skrev i meddelandet
news:bp1ali$1js2t8$[hidden email]...
> Mikael,
>
> I think your problem is that the proto objects do not understand
> #perform:withArguments:; if you steal Object's code for it, the
troublesome

> case should start to work.
>
> Have a good one,
>
> Bill
>
> --
> Wilhelm K. Schwab, Ph.D.
> [hidden email]
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Unexpected ProtoObject behaviour

Blair McGlashan
In reply to this post by Mikael Svane
"Mikael Svane" <[hidden email]> wrote in message
news:bp1752$1iquv1$[hidden email]...
> I have a number of ProtoObject subclasses in different packages that add
> behaviour to a Model subclass by forwarding failed messages using
> #doesNotUnderstand:. I have choosen to do it this way, because I cannot
add
> the added behaviour by subclassing the model, which has other subclasses
> that also need the new behaviour, which requires the use of additional
> instance variables and therefore cannot be implemented using loose
methods.

Three options you would have here are:
1) "Reserve" all the instance variables in the base package.
2) Use indexed instance variables encapsulating access to them through
accessor methods so that they appear no different to named instance
variables accessed in that way.
3) Use properties,. i.e. #propertyAt:[put:] and friends. The properties are
stored in a global dictionary by default, but you can make them much more
efficient by providing your own PropertyManager held in an instance
variable. [Actually it is easiest to implement a similar mechanism using an
identity dictionary held in an instance variable with the extra variables
keyed by symbolic name, because the property methods are not as well
factored as they might be].
4) Use the package pre-install script to add the instance variables
referenced from your loose method, and the post-uninstall script to remove
them.

Of these I would favour (4), but this might cause you problems if any of the
objects in question are stored using STB. If that is the case  then (3)
(with a private property manager) is a reasonable option. (2) has potential
STB conversion issues  as well, but is otherwise a good approach. (1) is
suitable if the set of extra instance variables is likely to be relatively
static.

Regards

Blair