Behaviors vs Modules

David Simmons David.Simmons at smallscript.com
Fri Feb 22 23:38:42 UTC 2002


Hi Anthony,

You do realize that you are largely describing the design and existing
implementation of the SmallScript language and its superset of
Smalltalk?

    See: www.smallscript.org

You might want to explore its implementation which has been refined over
many years of work (from QKS Smalltalk etc) in the areas of namespaces,
modularization, and selector namespace facilities.

As I've mentioned in other threads, I really would like to see
convergence/compatibility between Smalltalk dialects as things progress
(rather than divergence and incompatibility).

Not to mention the fact that there are a lot of subtleties and there is
a very non-trivial amount of learning and design ideas that are
incorporated into SmallScript to make these facilities cleanly and
efficiently within a simple unified module. 

I.e., there should be no reason to re-invent the ideas purely from
scratch when there is at least one existing Smalltalk implementation
that can be "mined/explored" for building and evolving the squeak
services in this area.

-- Dave S. [SmallScript Corp]

SmallScript for the AOS & .NET Platforms
David.Simmons at SmallScript.com | http://www.smallscript.org


> -----Original Message-----
> From: squeak-dev-admin at lists.squeakfoundation.org [mailto:squeak-dev-
> admin at lists.squeakfoundation.org] On Behalf Of Anthony Hannan
> Sent: Friday, February 22, 2002 3:38 PM
> To: squeak-dev at lists.squeakfoundation.org
> Subject: Behaviors vs Modules
> 
> Obviously we need modules and clear dependencies between them so we
can
> load only what we need.  However, I don't like having these
dependencies
> defined separately, rather they should be extracted from the code.
> Please consider the following proposal for restructuring behaviors in
> Squeak.  It enables behaviors to be modules, ie. a behavior knows, by
> looking at its methods, which other behaviors it depends on.  And it
> enables multiple inheritance, or more correctly, mixins.
> 
> Structure:
> - A protocol is a list of selectors commonly viewed together.
> - Each protocol has a default behavior (a method for each selector)
but
> the methods cannot contain direct instance variable references, they
> must use accessors.
> - Each selector belongs to one and only one protocol.  If two
selectors
> have the same name, they must be in separate protocols and each must
be
> prefixed with their protocol name when referenced by name.  For
example,
> [obj morph.step] vs. [obj debugger.step].  The prefix can be left off
if
> it can be assumed from the context.  For example. the "morph." prefix
> can be assumed when "step" is called from within other morph methods.
> - A class can implement (override) any selectors of any protocols.
> - A class can inherit variables and methods from a superclass the same
> way as today.
> - Classes will not have to inherit from Object since all of Object's
> methods can be put in default behaviors of respective protocols.
> - Classes will have fewer methods, only those that need overriding.
> Only 10% of all selectors in 3.2gamma are overriden.  Here is the
> calculation I used:
>   | overriden all |
>   overriden _ IdentitySet new.
>   all _ IdentitySet new.
>   Smalltalk allBehaviorsDo: [:cls |
> 	sup _ cls superclass.
> 	cls methodDict keysDo: [:sel |
> 		all add: sel.
> 		(sup notNil and: [sup canUnderstand: sel])
> 			ifTrue: [overriden add: sel]]].
>   (overriden size / all size) asFloat "=> 0.097"
> 
> Interpretation:
> - If a message selector is not in the receiver's class or superclasses
> then use the selector's default method.
> 
> Loading:
> - A Smalltalk expression now knows, via the selectors it calls, which
> protocols and corresponding default behaviors it depends on.  So
> starting from a Smalltalk expression we can trace selectors and
methods
> recursively and load all default behaviors that will be needed.
> - Classes can be loaded on demand with their instances or when
> referenced directly.  We only need to load the class methods that
> override protocols already loaded, we know other protocol methods will
> not be used.  We then trace the loaded class methods, like above, and
> load more default behaviors and class behaviors if needed (we only
load
> class behaviors of already loaded classes).
> 
> Conclusion:
> 	In this scheme, every object understands every selector because
the
> default method will be invoked if the object does not override it.
This
> is ok since the default method will either respond with
> subclassResponsibility (equivalent to doesNotUnderstand) or will call
> another method that the receiver may override.  So a class can easily
> add/mixin behavior just by implementing some core methods without
having
> to be a subclass.
> 	When programming a message send you inherently know which
protocol
> you
> are targeting.  This scheme makes that explicit allowing us to see
> dependencies between behaviors and protocols.  The requirement to
> unambiguate a selector by prefixing if necessary, I think is justified
> and would be rare.  If there is confusion about which protocol is
meant,
> it probably means, either the selector should be in its own seperate
> protocol, or the selector should be divided into two selectors with
> different names.  For example, should #at: be in "array" protocol or
> "dictionary" protocol?  Really it should be in a common protocol
called
> "collectionAccessing" or "indexing" and removed from "array" and
> "dictionary".
> 	Initially we can start out with every selector being in its own
> protocol.  Then we can combine selectors into protocols defined by
> method categories, leaving out selectors that are already in other
> protocols (the image converter would do all this).  For example,
> selectors in Morph stepping would go into the "morphStepping" protocol
> and all its methods that don't access instance vars directly would go
> into the protocol's default behavior.  Methods that have inst var refs
> would stay with the Morph class, while their corresponding methods in
> the default behavior would be "self subclassResponsibility".  Now any
> class can inherit morphStepping behavior just by implementing some
core
> methods that the default behavior relies on.  You will be able to
query
> a behavior to find out which selectors it sends to 'self' that it does
> not implemented.
> 	Small classes that only define differences from the default
behavior
> decouple the main algorithms from the special cases.  Also, senders
and
> implementors queries will be more accurate because it will be protocol
> specific.
> 
> What do you guys think?  I'm thinking of making this my next project.
> Cheers,
> Anthony





More information about the Squeak-dev mailing list