Prototypical objects in Dolphin

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

Prototypical objects in Dolphin

Andy Bower
Folks,

An interesting post came up in c.l.s recently with someone wanting to see if
instance based behaviour could be added to objects in Smalltalk (and in this
case Dolphin). Rather than cross post my reply (which might result in excess
pollution) I've just decide to post my reply separately here. Some of you
may find this amusing to play with.

"Artur Biesiadowski" <[hidden email]> wrote in message
news:[hidden email]...

> >> Is there any smalltalk-like system which allows you to redefine
> >> behaviour of single instance ? Instead of redefining method for class,
> >> do it only for single instance and only then maybe propagate it to
> >> entire system.
> >
> > You can do that in Smalltalk.  Or Lisp.
>
> So I can get Dolphin Smalltalk for example, create collection of 20
> instance of my class, select one of them, do something (what method
> should I call?) and normal method edition window will appear, but just
> modifying code for this single instance ? And if I'll clear contents of
> array, what will happen to code ? It will be deleted automagically or
> orphaned ? In latter case, how can I access it later ?

Yes, and this is how you do it. The following code is for Dolphin. Most
Smalltalks will be able to do something similar but the implementation will
typically be via private methods and so won't be consistent between
dialects. If you haven't got a copy of Dolphin yet then try this with the 30
day Dolphin Professional trial version available at:

http://www.object-arts.com/Trial

Fire up the IDE and open a workspace. Copy the following into the workspace,
select it, and then choose Workspace/File it in.

+++ snip after this line +++

!Object methodsFor!
assumeInstanceBasedBehavior
    "Private - Make the receiver a prototypical instance of it's own private
class. From this point on
    the instance may have it's own behaviour modified or added to."

    | metaSuperclass newMetaclass newClass |

    "Create a private new metaclass"
    metaSuperclass := self class class.
    (newMetaclass := Metaclass new)
        methodDictionary: MethodDictionary new;
        instanceSpec: metaSuperclass instanceSpec;
        superclass: metaSuperclass.

    "Create a private instance of this metaclass as the new class"
    (newClass := newMetaclass new)
        methodDictionary: MethodDictionary new;
        instanceSpec: self class instanceSpec;
        setName: ('_', self class name) asSymbol;
        superclass: self class.

    self becomeA: newClass.! !

    !Object categoriesFor: #assumeInstanceBasedBehavior!private! !

+++ snip before this line +++

I'm not sure the formatting will make it through NNTP but it should work
anyway. This is a new method added to Object (and in this case I think it
*is* appropriate to extend Object - just harking back to another thread).
The method creates a new private (hidden) class and metaclass pair for any
object that has #assumeInstanceBasedBehavior called on it. This pair hold
their own private method dictionaries so prototypical methods can be added.
Note you can add both instance and class based prototypical methods.

The new classes will not be visible in the standard browsers but could be
made so if necessary. They will also disappear and be garbage collected when
the prototypical object has no remaining  references.

Let' test this out. Copy the following into a Dolphin workspace and execute
each line individually (place the cursor on the line and press Ctrl+E).
Stuff in "" is comment. When you see a line with "Ctrl+D" then press this
and it will evaluate the line and display a result. We'll work on Dates for
a simple but rather boring demo.

a := Date today. "Ctrl+D"
b := Date today.
c := Date today.

Three dates. Add them to an array (your suggestion)

array := Array with: a with: b with: c. "Ctrl+D"

Let's make the first two have prototypical behaviour.

a assumeInstanceBasedBehavior.
b assumeInstanceBasedBehavior.

Ask for the weekdays of the days in the array.

array collect: [:each | each weekday ]. "Ctrl+D"

No surprise there. Even thought the first two have the capability of
prototypical behaviour they are inheriting from their original class (Date).
Now let's add that "Friday feeling" to the first date only. We'll change the
behaviour of the #weekdayIndex method to always answer 5. Then see what
happens when we ask for the #weekday again (which makes use of
#weekdayIndex). Note we use the standard compiler to compile in the new
method into a's class.

a compile: 'weekdayIndex ^5'.

Now ask for the days again:

array collect: [:each | each weekday ]. "Ctrl+D"

Assuming that it's not actually Friday when you try this you should see a
difference. Notice that only the first date has got the new behaviour. The
second prototypical date is still inheriting directly from Date. Try
modifying it's code for a Saturday.

a compile: 'weekdayIndex ^6'.
array collect: [:each | each weekday ]. "Ctrl+D"

Now lets see how we can tell these are different from normal Dates

array collect: [:each | each class ]. "Ctrl+D"

Try looking for _Date in the Class Hierarchy Browser; it should be nowhere
to be found. You can find the hidden classes by a roundabout route:

(Metaclass allInstances collect: [:each | each instanceClass]) select:
[:each | each superclass == Date] "Ctrl+D"

Now free up our variables and look again:

a := b := c := array := nil.
(Metaclass allInstances collect: [:each | each instanceClass]) select:
[:each | each superclass == Date] "Ctrl+D"

You should find that the _Date classes have disappeared automagically.

I notice from your original post that you wanted to be able to view the
instance based methods in a browser. This would be fairly easy to arrange
but is beyond the scope of this excercise. Still, I hope you've found the
above to be amusing and food for thought.

Best Regards,

Andy Bower
Object Arts Ltd.
http://www.object-arts.com
---
Are you trying too hard?
http://www.object-arts.com/Relax.htm
---


Reply | Threaded
Open this post in threaded view
|

Re: Prototypical objects in Dolphin

Andy Bower
Sorry there was a typo in my previous post at the point when things got
interesting:

> a compile: 'weekdayIndex ^5'.
> a compile: 'weekdayIndex ^6'.

These should be:

a class compile: 'weekdayIndex ^5'.
b class compile: 'weekdayIndex ^6'.

Best Regards,

Andy Bower
Object Arts Ltd.
http://www.object-arts.com
---
Are you trying too hard?
http://www.object-arts.com/Relax.htm
---