patterns and Self

Jecel Assumpcao Jr jecel at merlintec.com
Wed Dec 13 17:54:51 UTC 2000


As promissed, here are some quick comments from a Self programmer's
viewpoint on the patterns in the "Design Patterns" book by Erich Gamma,
Richard Helm, Ralph Johnson and John Vlissides. The numbers in
parenthesis are the page numbers where each pattern is described.

I hope this helps,
-- Jecel

Creational Patterns
--------------

===> Abstract Factory(87):

I have suggested that it might be interesting to add abstract types to
Self in the form of interface (to use Java terms) objects. This would
be a good use of this pattern. Instead of writing 

               a: list copyRemoveAll

which refers to a specific prototype (list) directly, we could have

              a: interfaces sequence getOneFor: 'fifo'

Of course, with dynamic types this pattern is considerably simpler in
Self than in the book. I can't think of an example where this is used
in Self 4.1.2.

===> Builder(97):

This goes against the idea of creating new objects by simply cloning an
existing one. Of course, sometimes cloning is anything but simple. See
the copy method for morphs, for example. But it is probably better to
stick with the current Self style of stuffing all the complexity in the
'copy' method instead of creating separate "builder" objects.

===> Factory Method(107):

It is hard to see what the fuss is all about when you have dynamic
types and cloning. Just put a prototype of the "concreteProduct" in a
slot in the prototype of the "concreteCreator" and patch the copy
method to go down one level, here. See the low level graphical
framework in Self (canvas, windows, graphics contexts...) for an
example. No big deal.

===> Prototype(117):

This *is* a prototype based language. You can't avoid using this
pattern if you want to! No big deal.

===> Singleton(127):

All objects in Self are singleton unless they have traits clonable (or
some suitable replacement) as one of their ancestors. No big deal.

Structural Patterns
--------------

===> Adaptor(139):

This is *so* much simpler with implicit, dynamic delegation (data
parents). When wrapping an objects with many methods, you only have to
worry about the ones you will need to change, not about all of them.
And Self really makes this pattern more powerful by allowing you to
override data slots as well as method slots (even better: you can
override a data slot with a method slot and vice versa). The only thing
to watch out is how to handle copying and how to avoid having the
adapted object's identity "leak out". Reflection might help with these
problems. I don't know of any examples in Self 4.1.2.

===> Bridge(151):

You could use implicit delegation for this pattern, but the example in
Self (canvas) uses explicit delegation instead.

===> Composite(163):

Morphs are a great example of this. I am not sure that any Self
features help very much, here, other than having dynamic typing make
what objects can be plugged into what others more flexible.

===> Decorator(175):

It would be more pleasing, in my opinion, to use data parents (implicit
delegation) for this pattern. I don't know of any examples where it is
used in Self 4.1.2.

===> Facade(185):

I don't think Self makes this pattern simpler than in other languages.
I was going to say that 'desktop' could be an example of this, but that
is pushing it a little....

===> Flyweight(195):

I would say that Self's advanced inlining compiler technology makes
this pattern less necessary than in other systems. This pattern is also
used as a classic example of the advantages of reflective systems (see
the Open Implementation pages).

http://www.parc.xerox.com/spl/projects/oi/workshop-94/foil/main.html

Oddly enough, there are examples of this in Morphic. There are several
cases where the strategy pattern should have been used but the
information was represented as simple integers instead (see alignLeft,
alignCenter and alignRight in columnMorph and similar options in
related morphs). This is a design bug - I think the flyweight pattern
should never be used in Self.

===> Proxy(207):

Exactly the same comment as for Adaptor. Except that there are plenty
example of this in objects named, oddly enough, "proxies".

Behavioral Patterns
---------------

===> Chain of Responsibility(223):

The event handling in the user interface partly uses this pattern.
Having implicit delegation might be nice, but I am not sure it would
make much of a difference, here.

===> Command(233):

Event objects in the user interface could be considered an example of
this. I think that this is nicer to do in Self since making lots of
objects that are a little different isn't as bad as when you have to
create a different class for each one.

===> Interpreter(243):

The only example that comes to mind is tinySelf 1. While the Self
language itself doesn't make this pattern much simpler, being able to
develop and interpreter in a dynamic user environment really helps. I
think that most cases where this pattern might be used could be better
implemented as a parser generated by Mango instead.

===> Iterator(257):

As Smalltalk Stream classes show, this pattern is much easier to
implement in dynamically typed languages. I don't know of any examples
in Self 4.1.2 and sometimes miss them a lot. My students implemented
iterators for matrix objects (for an unfinished 3D GUI project) and
that made a lot of the higher level code considerably simpler.
Iterators are important in languages like Self and Smalltalk that have
a very awkward syntax for accessing vector elements.

===> Mediator(273):

Hmmm... I am not sure, but the damage/redraw logic distributed between
morphs and the worldMorph might be considered an example of this. I
don't see that Self is particularly helpful in this case.

===> Memento(283):

Don't you just pity the poor slobs who have to program with systems
that can't save Snapshots?  :-)

You don't need this pattern with Snapshots, but in Self we do have it
in the form of the Transporter. It would be nice to replace these two
great tools with a real persistent object store.

===> Observer(293):

I would say that the damage/redraw code also includes an example of
this pattern. Self doesn't help with this either, but a reflective
layer might.

===> State(305):

Who needs this when you can have data parents? See the various tree
objects in Self 4.1.2 as an example of why we can live without this (or
as an example of how to implement this with implicit delegation,
depending on your viewpoint).

===> Strategy(315):

This can also be implemented as data parents, but I have used explicit
delegation in my own programs instead. In the latter case Self doesn't
bring much to the party.

===> Template Method(325):

This is used in many places in Self, including in the C++
implementation of the virtual machine. For some reason I tend to think
of the Beta language when I look at this pattern, but it is easy in
Self as well.

===> Visitor(331):

I can't think of any examples of this in Self, though some of the
runtime code generated by Mango might qualify.



More information about the Self-interest mailing list