Canvas is-an Encoder?
Marcel Weiher
320089961391-0001 at t-online.de
Wed Jun 28 09:35:49 UTC 2000
> From: "Lex Spoon" <lex at cc.gatech.edu>
>
> Why is Canvas a subclass of NullEncoder and FlattenEncoder, lately? It
> seems to be something added to make the Postscript support work,
but the
> solution seems kinda strang--Encoding and drawing really seem like
> separate issues to me. For example, should the same class implement
> drawCircle: and initWithTarget:? fillRectangle: and writeObject: ?
Ahem, yes, it should, but the isa relationship could still be
removed as things are right now.
The ping-pong double-dispatch mechanism that the encoders make
available is actually very useful for a display situation, so useful
that a less generic version of the same mechanism has been
independently added to Canvas. Of course, IMNSHO it would be much
cooler to just reuse the encoder's version, because that's why I put
it there!
On the history of the mechanism, Dan's paper describing this
mechanism (early 80ies, I think) actually used graphical 'ports' as
its running example, IIRC.
When you think about the display process more closely, it starts to
make a lot of sense, because how to display an object is something
that actually has to be "negotiated" between a specific display and a
specific object, and it is also an encoding task. Descriptions of
graphical objects are encoded into commands to drive a display,
wether these commands happen to be direct calls to routines, encoded
commands to display accelerators.
The "negotiation" phase also makes a lot of sense because often
times an optimization that is vital for one type of display yields to
unacceptable output for a different type. Encoding all this behind
an opaque interface is possible, but letting display and/or object
adapt is a much more squeaky solution. What's more, specialized
algorithms/capabilities/hardware can be taken advantage of between
specific objects and specific displays (always taking "display" to
mean some sort of graphical output device or format).
The generic #writeObject: interface makes it possible to reuse code
in a wide variety of different circumstances. For example,
Canvas/Morph currently have specific code to render the submorhs,
traversing the collection. This code is redundant because
'flattening' object hierarchies is what the FlattenEncoder does,
except that it does it for all sorts of different applications, not
just a canvas. It can do this for all these different circumstances
because #writeObject: will automatically do the right thing for the
subobjects and the actual encoder. It's not a big thing, but these
'flattening' patterns occur all over the image, whereas this one
implementation would actually suffice.
> With multiple inheritance, it would seem reasonalbe to have
> PostScriptCanvas be a subclass of both Canvas and Encoder. But as
> things are, making Canvas a subclass of Encoder just for Postscript's
> sake seems strange. Why not just have an 'encoder' instance
variable in
> PostscriptCanvas?
It's not really just for Postscript's sake, although at present it
looks that way because the functionality that is provided is not
used, but rather duplicated. Call me biased, but it makes more sense
to me to remove the duplication...
Marcel
More information about the Squeak-dev
mailing list
|