generic views [Was: Tweak position?]

Howard Stearns HStearns at wisc.edu
Wed Feb 9 16:38:12 UTC 2005


I'd like to suggest a way to architect the problem technically. I  
realize it may duplicate what people are thinking, or be completely  
incompatible, or just plain irrelevant. Apologies. I've been lurking,  
but don't have the Squeak-specific background to know how far off the  
mark the following is.

In my experience, some attempts at multiple view presentations have  
failed because they fail to realize that there is more than one axis  
along which to make decisions about what is in common between  
presentations for different media-or-toolkits vs what is different.  
It's not just a matter of choosing inspector X or inspector Y, browser  
X or browser Y, at top level.

For example, media-or-toolkit X may want to share structure with Y for  
the two realizations of an inspector. In the HTML-generating world, for  
example, systems like uPortal separate the structure of the  
presentation (defined using XSLT) from the style of the components of  
that structure (defined using CSS).  An application is broken down into  
various structures used for presentation (the XSLT part), and in  
different contexts the same application data might use different XSLT  
to specify that structure. Separately, the various bits of structure  
that are produced by one XSL or another might be styled using the same  
CSS. Or they might well use their own CSS. The point is that the  
specification of structure and style are separated.

Of course, XSL and CSS don't provide for a lot of reuse of separately  
developed components. (If you're a language freak, you might be  
interested in IBM's Darwin Information Typing Archicture (DITA), which  
provides for multiple inheritance of XSLT by explicitly doing in XSL  
attributes exactly what a dynamic language implementation of multiple  
inheritance does under the surface. Neat stuff.)

In the late '80's I worked on a multiple axis view inheritance system  
that was used in a product for over 10 years and took the company  
through an IPO and two buyouts. We had a geometric expert system and  
needed to produce geometric and attribute interfaces to more than 10  
CAD systems (and growing). Some were 2d, some 3d, and all had quite  
different ways of getting information in and out. Our expert system  
used a message-passing style of OO.

    For output, we created a Writer object representing the capabilities  
of the CAD system. Each Writer had primitives for basic capabilities  
like line and arc. Some of these produced results right away, and  
others kept state that was later dumped when the serial connection was  
closed. Writers for a CAD system that worked like other CAD systems  
could inherit from the corresponding Writers. (We had multiple  
inheritance, but didn't use it much for Writers. However, 2D CAD  
systems did tend to inherit along a branch that inherited the same  
3D-to-2D projection code.) Different styles were produced by providing  
initialization arguments to a Writer, by side-effecting Writers during  
use, or by subclassing the Writers altogether.

    But we did not simply hand one of our geometrical expert-system  
application objects to the Writer for output, nor did we define output  
methods on the application object that invoked stuff on the Writer.  
When asked for serial output, the Writer was asked to produce a  
delegation object for the application object. Our applications had a  
whole tree of application objects, and the machinery cached the  
Writer-specific delegations so as to produce a shadow tree of  
delegation objects. New serializations (e.g., a new file) cleared the  
cache. Each shadow/delegation object pointed back to the application  
object as needed. (Not unlike Tweak?) The Writer-specific  
shadow/delegation objects often had complex structure of their own. For  
example, a 3D Cube application object might present on solid-modeling  
CAD systems as a single Cube solid, while wireframe CAD systems might  
use 12 Line objects. The Writer for the solid modelers produced a  
shadow object that just delegated everything back to the Cube  
application object. However, the Writer for the wireframe CAD systems  
produced shadow objects that had their own little tree of 12 Line  
objects. The Line objects were, in turn, output in the normal way, just  
as if they were the original application objects. This allows for a  
huge amount of reuse in how different CAD system produce similar  
structures, even if the syntax of individual item representation was  
quite different.

   Even though we had hundreds of application objects in the system, and  
customers created thousands more, we regularly created presentations  
for new CAD systems in a week or so. Mostly it was a matter of defining  
only the most primitive methods for the new Writer, reusing a lot of  
the delegation objects.

My thinking is that the internal structure of browsers and inspectors  
and such are often appropriate to share between different graphics  
systems, somewhat orthogonally to how the graphic systems themselves  
work.

Since that time, the Lisp community has developed a much more  
straightforward way to do this, using multiple dispatch. Generic  
functions are like Block objects. However, instead of dispatching  
between methods based on the "receiver" (or what is effectively the  
first argument), the dispatch is made based on all the arguments. In  
the Common Lisp Interface Manager (CLIM), a presentation is created by  
calling a generic function that dispatches on the application object,  
the application-defined View for the current context, and the Media (a  
stream) on which the presentation is to be displayed.  Views can  
inherit from other Views, Media can inherit from other Media. Methods  
for the presentation generic functions can be created for any specific  
combination of application object, View, and Media, and these methods  
can (and frequently do!) call the next more general applicable method.  
(Presentations are actually objects that could be further broken down,  
somewhat like the shadow objects in the CAD output. But in practice,  
the multiple dispatch gives sufficient flexibility with reuse, that I  
think applications rarely messed with the internals of Presentations.)   
The process is essentially doing more flexibly in one line what the CAD  
output system did by dispatching to Writers and then to delegation  
objects and then back to the Writer. The whole mechanism fosters even  
more code reuse when the dispatch can use a form of multiple  
inheritance within application object, View, and Media. (The tradeoff  
is basically more branches within the objects, or more arguments for  
dispatching within the generic function.)  Generic functions are pretty  
easy to write in Smalltalk. (Mine at  
http://groups-beta.google.com/group/comp.lang.smalltalk/browse_frm/ 
thread/ad5d131840cccafd/b6e691d9834f8b90 just uses the class precedence  
list implied by Smalltalk's normal single inheritance, but it could  
easily be changed to use any more complex property.)

-Howard






More information about the Squeak-dev mailing list