[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
parent slots implemented as methods
Hello, sorry this posting is so long ...
A while ago I asked if it was inconsistent that parent slots cannot be methods.
There were questions about what this would mean, and why it might be useful,
and also Mario Wolczko pointed out that it can already be done in the VM - with
the behavior that if an object with a parent slot 'parent' was sent the message
'parent' then it would evaluate the method, and the object would inherit from
the _method_object_ (*not* the object resulting from the evaluation of the
method).
I 'stumbled' across a 'simply delightful' use of having parent slots as
methods such that the inheritance is from the result of the method
evaluation (OK - there are problems about what this might mean - but
I'll try to explain what I mean)
If you are familiar with the use of 'data parents' then skip this paragraph.
A useful 'pattern' in Self programming is using sort of 'wrapper'
objects to add state/behavior to an object - e.g. if you have a point
and want to give it a color and associated behavior, you could have a
'color wrapper' which has an instance specific assignable slot for the
color, some suitable methods, and an assignable parent slot which is
set to the point to which you want to add color.
A real problem with using 'data parents' is what to do with the slots
that you would like to share between all 'wrappers'. If you put them in
the 'wrapper' itself then there are problems of inconsistencies if you
want to change them, and conceptually you have lots of copies of things
that you really wanted to be shared, which is not a good thing
(although maybe copyDown slots could be used to solve this problem).
If you try to put them in a parent object of all wrappers (a different
parent slot to the assignable one whose value is the wrapped object)
then there are problems of ambiguous selectors and not being able to
override slots of the wrapped object (unless you put lots of
disambiguating methods in the wrapper object or modify
'ambiguousSelector:...')
The proposed solution to the above problem is to have a non-parent
assignable slot in the wrapper to refer to the wrapped object, and a
parent object shared by all wrappers, which itself has a parent slot
which is a method which evaluates as the wrapped object. Therefore, all
wrappers would share the same parent object, which could have methods
overriding ones in the wrapped object; and there would be no ambigity
problems, as the parent of the parent of each wrapper would be the
wrapped object specific to each wrapper.
Madness? Maybe; but in case you don't understand/believe that such a
thing is possible/useful, please try the example self code at the end
of this mail. In this example there is a wrapper called
'wrapperExample' and an object to be wrapped called
'exampleWrappedObject'. Create a wrapped version of this object by
evaluating 'wrapperExample copyFor: exampleWrappedObject'. Try sending
this object messages 'aMethod' and 'aNonOverriddenMethod' and have a
look at the code to see what's going on. Having a parent slot
implemented as a method is faked by the parent of the parent of
'wrapperExample' by using delegation and 'undefinedSelector:...'. If
parent slots could be implemented using methods then the method
'myParentWillBe' in the parent of 'wrapperExample' would be a parent slot.
Ivan (obfuskating on thin ice towards madness).
------------
'$Revision:$'
'
Copyright 1992, 1993, 1994, 1995 Sun Microsystems, Inc. and Stanford University.
See the LICENSE file for license information.
'
'-- Module body'
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
exampleWrappedObject = bootstrap setObjectAnnotationOf: bootstrap stub -> 'globals' -> 'exampleWrappedObject' -> () From: ( |
{} = 'ModuleInfo: Creator: globals exampleWrappedObject.
'.
| ) .
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'exampleWrappedObject' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
aMethod = 'the result of some method'.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'exampleWrappedObject' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
aNonOverriddenMethod = 'aNonOverriddenMethod'.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'exampleWrappedObject' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: InitializeToExpression: (nil)'
someAssignableSlot.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'modules' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
wrapperExample = bootstrap define: bootstrap stub -> 'globals' -> 'modules' -> 'wrapperExample' -> () ToBe: bootstrap addSlotsTo: (
bootstrap remove: 'comment' From:
bootstrap remove: 'directory' From:
bootstrap remove: 'fileInTimeString' From:
bootstrap remove: 'postFileIn' From:
bootstrap remove: 'revision' From:
bootstrap remove: 'subpartNames' From:
globals modules init copy ) From: bootstrap setObjectAnnotationOf: bootstrap stub -> 'globals' -> 'modules' -> 'wrapperExample' -> () From: ( |
{} = 'ModuleInfo: Creator: globals modules wrapperExample.
CopyDowns:
globals modules init. copy
SlotsToOmit: comment directory fileInTimeString postFileIn revision subpartNames.
\x7fIsComplete: '.
| ) .
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'modules' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot\x7fVisibility: public'
comment <- ''.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'modules' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot\x7fVisibility: public'
directory <- 'applications'.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'modules' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: InitializeToExpression: (_CurrentTimeString)\x7fVisibility: public'
fileInTimeString <- _CurrentTimeString.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'modules' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
postFileIn = ( |
|
transporter moduleDictionary resetFillingSemaphore.
snapshotAction addSchedulerInitialMessage:
message copy receiver: transporter moduleDictionary
Selector: 'resetFillingSemaphore'.
resend.postFileIn).
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'modules' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot\x7fVisibility: public'
revision <- '$Revision:$'.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'modules' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot\x7fVisibility: public'
subpartNames <- ''.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
wrapperExample = bootstrap setObjectAnnotationOf: bootstrap stub -> 'globals' -> 'wrapperExample' -> () From: ( |
{} = 'ModuleInfo: Creator: globals wrapperExample.
'.
| ) .
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
parent* = bootstrap setObjectAnnotationOf: bootstrap stub -> 'globals' -> 'wrapperExample' -> 'parent' -> () From: ( |
{} = 'ModuleInfo: Creator: globals wrapperExample parent.
'.
| ) .
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'wrapperExample' -> 'parent' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
aMethod = ( |
| resend.aMethod,' with something added').
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'wrapperExample' -> 'parent' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
copyFor: x = ( |
c.
|
c: _Clone.
c wrappedObject: x.
c).
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'wrapperExample' -> 'parent' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
myParentWillBe = ( |
| wrappedObject).
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'wrapperExample' -> 'parent' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
parent* = bootstrap setObjectAnnotationOf: bootstrap stub -> 'globals' -> 'wrapperExample' -> 'parent' -> 'parent' -> () From: ( |
{} = 'ModuleInfo: Creator: globals wrapperExample parent parent.
'.
| ) .
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'wrapperExample' -> 'parent' -> 'parent' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: FollowSlot'
undefinedSelector: s Type: t Delegatee: d MethodHolder: m Arguments: a = ( |
|
s sendTo: self DelegatingTo: myParentWillBe WithArguments: a).
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: InitializeToExpression: (nil)'
someWrapperAssignableSlot.
} | )
bootstrap addSlotsTo: bootstrap stub -> 'globals' -> 'wrapperExample' -> () From: ( | {
'ModuleInfo: Module: wrapperExample InitialContents: InitializeToExpression: (nil)'
wrappedObject.
} | )
'-- Side effects'
globals modules wrapperExample postFileIn