Squid modules vs. ClassBoxes (was: Squid language)

Anthony Hannan ajh18 at cornell.edu
Sun May 4 17:56:34 UTC 2003


I forget to clarify my description of Squid behaviors/modules with an
example.  I will use the example presented in the ClassBoxes paper
(http://scgwiki.iam.unibe.ch:8080/SCG/559) while comparing the two
module schemes.

A classBox is a module containing classes and local class extensions to
imported classes.  It imports classes from other classBoxes.  Global
vars must refer to local or imported classes, but messages may refer to
any interface.  Interfaces are global not imported.  For example, it may
send the #do: message to some argument without importing the Collection
interface.

I know current Smalltalk does not bind messages to interfaces, but Squid
does.  I believe it is important to capture the interface because the
programmer has to think of the interface to come up with the right
message.  But as soon as he compiles the method the interfaces he
thought of are lost.  We can easily capture the interface by having the
compiler lookup messages in interfaces visible to the module.  There are
many benefits to capturing interfaces and few costs.  Interfaces add
structure explicitly defining module boundaries.  It also facilitate
type inference.  The cost is modeling these interfaces and capturing
them, but Squid modules makes this easy.  Modeling interfaces is a key
divergence between Squid modules and ClassBoxes.

A Squid module is a set of methods whose public methods define the
module's interface.  A module import other modules making their
interfaces available to local methods.  The module's methods primarily
serve to define selectors for the interface, but their implementation
define default behavior that is executed if the receiver class does not
implement is own version.  So the Collection module would define #do: as
well as #collect:, #select:, etc.  It would implement #collect: and
#select: using #do:.  A class such as OrderedCollection would override
#do: and automatically inherit the default implementation of #collect:
and #select:.  The OrderedCollection would get this behavior just by
implementing #Collection.do: without needing to explicitly subclass from
Collection.  This allows open multiple inheritance.  Notice,
#Collection.do: is the full selector name to distingush which interface
you are refering to in case some other module also defines #do:.  In
practice, it is likely that #do: will be unique among all imported
modules so the prefix can be elided.

A Squid class can only implement methods previously defined in some
module, thus overriding it.  A class can implement private helper
methods but these can not be called from outside the class.

Now for the example.  The ClassBox paper presents an example of writing
a LinkChecker that parse an HTML page into a HTML parse tree, then uses
a generic visitor to visit each node in the parse tree.  The special
LinkChecker visitor responds to #visitLink: by pinging the link
destination to see if its up.

The HTMLVisitor classBox extends each HTMLParseNode in Squeak with an
#acceptVisitor: method and defines a generic HTMLVisitor class.  The
LinkChecker classBox defines a subclass of HTMLVisitor called
LinkChecker that overrides #visitLink: with the code that pings the
link.

In Squid, the HTMLVisitor module would define #acceptVisitor: and
#visitHead:, #visitBody:, #visitLink:, etc. and implement them with
default behavior.  Each HTMLParseNode class would be directly extended
with #HTMLVisitor.acceptVisitor: containing the appropriate
implementation.  A new LinkChecker class would be created and extended
with #HTMLVisitor.visitLink: containing the ping code.

The main difference is that Squid add extensions directly to the class
while ClassBoxes keeps them in the classBox.  But this really is just an
implementation difference the two are equivalent.  A browser could
easily show/edit methods by module or by class in either scheme.  In
both implementations, the extension methods are bound to the owning
module/classBox as well as the base class.  In Squid the extension
methods reside on the class but are bound to the module via the selector
prefix.  In ClassBox, the extension methods reside in the classBox but
are bound to the class via the class extension syntax.  Actually,
internally ClassBox also puts the extension methods directly in the
class method dictionary with a classBox prefix.

In the ClassBox example, they also extend the Socket class with an
alternative #ping: method in the LinkChecker classBox.  This can be done
as well in Squid by defining a #ping: method in a LineChecker module
then extending Socket with #LinkChecker.ping:.

However, the ClassBox implementation may be implying that this
alternative #ping: method will be called even if not called directly
from a LinkChecker.visitLink:.  This implies dynamic context influencing
method lookup.  This is different then typical modules whose lookup is
determined lexically.  Dynamic lookup violates encapsulation and is
dangerous.  Suppose your code triggers an execution path you did not
anticipate that calls #ping: expecting the old behavior.  Because it is
runs in your context it will use the new #ping: version and break.  I'm
not sure ClassBox is proposing this but I got this impression.

I would handle changes like this to #ping: not using modules but rather
with long-lived transaction/version.  You would run your app within a
certain version.  But this is another topic.

In Squid class are separate from modules while in ClassBox classes
reside in modules.  The ClassBox way forces the classes to import the
same modules that the rest of the module imports.  Squid allow classes
to import only what it needs without importing what the rest of the
module needs.

Also, Squid allows controlled overrides.  A subclass may only override
methods that call classResponsibility or classMayOverride.  This provide
an explicit "subclass/polymorphic" interface.  For example, the
Collection module may define #select:, without override capability
making sure it is not overriden improperly.  Or it may define a private
helper method it does not want subclasses to intercept and abuse.  In
general though most public methods will be implemented with
classMayOverride capability.

Finally, not only is Squid modules an alternative to ClassBoxes it is
also an alternative to Traits.  Each module would be a trait and any
class could include any trait just by implementing key
classResponsibility methods of the trait.

Cheers,
Anthony



More information about the Squeak-dev mailing list