Modules instead of Behaviors (was: Generalized Object Modules Design)

Anthony Hannan ajh18 at cornell.edu
Wed Mar 6 04:22:37 UTC 2002


"Richard A. O'Keefe" <ok at cs.otago.ac.nz> wrote:
> Anthony Hannan <ajh18 at cornell.edu> wrote:
> 		A module is a group of related methods from many classes that fullfill
> 	a single functionality.  A module is equivalent to a method category
> 	like 'printing' which may cross many classes.  All methods in 'printing'
> 	from all classes would end up in a single module called 'Printing'.
> 
> I don't propose to comment on the rest of his proposal.
> But this claim is clearly wrong.
> If I have some XML classes (and I do), and I have methods for
> printing (and I do), they are primarily *about* XML, not *about* printing.
> If you loaded the XML classes, you might or might not want the printing
> methods; arguably one could chop an XML package up along
> common/parsing/printing/visiting lines, with parsing, printing, and
> visiting optional.
> But if you loaded the "Printing" module in order to print plain text,
> you _wouldn't_ want the XML printing methods loaded as well.

	You don't "load" modules as I have defined them you load
changesets/layers that add to modules, which I put off as another design
topic.  I'm sorry I should have used a different word other than
"module" to describe the object that holds a set of methods across
classes that fulfills a single functionality.  From now on I will call
this object a "functionality" (I would call it a "behavior" but that may
be confusing as well).  A whole 'Printing' functionality would rarely be
stored in single changeset.  A basic printing changeset would just add
methods for core class to the 'Printing' functionality.  The XML
changeset would add more #printOn: methods to the 'Printing'
functionality.
	We could decide to define functionality at the smaller protocol level,
ie. at the intersection of broad functionality ('Printing') and receiver
type.  For example, the broad 'Printing' functionality would be broken
up into at least an 'ObjectPrinting' functionality containing #printOn:
& #printString and a 'StreamPrinting' functionality containing #print:. 
But I would vote against this because this is too fragmented.
	So if we are going to stick with a broader categorization, the
fundamental question is: should we group methods by functionality or
class?  Remember, in either case the loadable unit (changeset/module)
may contain just subsections of classes/functionalities.
	I favor grouping methods by functionality over class primarily because
functionalities can be used as selector namespaces.  Classes can't be
used as selector namespaces because that would limit polymorphism.  Two
classes that implement the same selector would in fact be different
selectors if the class was the selector namespace.
	Grouping methods by selector namespace allows us to see precisely how
methods depend on each other.  Consider the case where a #printOn:
method sends #nextPutAll: to its argument.  When methods are grouped by
functionality/namespace we know all the possible methods of #nextPutAll:
that may be called, because when compiled #nextPutAll: will refer to a
specific SelectorBehavior in a specific functionality/namespace.  All
methods in that selectorBehavior and only those methods are candidates. 
If we don't have namespaces we have to search all classes to find all
methods that implement #nextPutAll:.  This is overkill since some
#nextPutAll: methods may be unrelated to streams. ie. they really belong
in a separate functionality/namespace.  This is the problem we see today
when looking at implementors/senders, we're not sure which of them
really apply without prior knowledge.  Also, having precisely the right
implementors together in a single selectorBehavior one pointer away from
its senders, will speed up type inferencing significantly.


> We can classify a method several ways:
>     - what class does it belong to?
>     - what encapsulation boundary/namespace does it live in?
>     - what other methods should it be loaded with?
>     - which of several syntaxes does it use?
>     - who wrote it/who has permission to revise it?
>     - which use cases is this needed for?
>     - what kind of action does this perform?
>     ...
> 
> Bertrand Meyer argued for years that classes should be used for
> everything, and then Eiffel acquired a notion of "cluster" (more or
> less a unit of linking) in its configuration language Lace.
> Ada and Common Lisp drive a wedge between classes and packages (which
> are encapsulation boundaries), Lisp drives a wedge between both and
> units of loading; units of loading can be bigger _or_ smaller than
> classes, bigger _or_ smaller than packages.
> 
> Because there are many ways to classify fragments of code, it is
> unlikely that a single mechanism can serve well for all of them.
> While a single mechanism can be very useful for what it does, I
> think it unlikely that a mechanism designed without at least
> _considering_ the other ways of classifying and structuring will
> have staying power.



More information about the Squeak-dev mailing list