Breaking up the image

Anthony Hannan ajh18 at cornell.edu
Wed Dec 11 17:22:06 UTC 2002


Daniel Vainsencher <danielv at netvision.net.il> wrote:
> It took a few minutes, but IIUC, this is an algorithm to extract
> everything else that's needed for running a certain package. Let's say,
> a pretty precise view of dependencies.

Yes.  Another caveat that I forgot to mention before is that
"overloaded" selectors are treated as one selector/meaning, and thus
bring in more methods than desired.  An overloaded selectors is one that
has more than one meaning and therefore not all behaviors for that
selector are polymorphic with each other.  For example, #red means the
color red for Color class, but the amount of red for color instances. 
These two would never be used polymorphically with each other, so in
essence they are really different selectors that happen to have the same
name.  Ideally, you would want them to be separate selectors, so you
only call one or the other and only bring in methods that implement that
one meaning.  Selector namespaces would solve this problem, and I have a
design for this in my version of multiple inheritance on my website on
the swiki (http://minnow.cc.gatech.edu/squeak/AnthonyHannan).

> Are you saying there's a way I can use this particular view of
> dependencies backwards, to help me find out all the Traits I can factor
> out and make into packages?

"Rough" traits can be extracted using step 1 alone.  This will reveal
traits that are shared between classes that aren't in the same class
hierarchy (modulo the overload problem described above).  The rest of
the algorithm can be used to divide up methods in each class into two
groups, those used by the package and those not used by the package. 
You can use this information to split those groups into separate traits.

Another alternative, which I think is the best in theory, is to use a
graph partitioning algorithm to partition our graph of classes and
methods into clusters.  Each resulting cluster would be a rough package
which can be further enhanced manually or maybe with some other
algorithms.  I'm no graph theory expert, but I think this might be the
best way to go.

Side Note:  I hope people realize that traits is just multiple
inheritance in disguise (as per last month's discussion under "Class
Dependencies").  The only difference is how 'super' and inst vars are
interpreted, but these can be resolved by using aliasing everywhere, and
using primitive accessors (so inst vars can be overridden/change slot
index).  So it might be easier to think in terms of multiple
inheritance.

Cheers,
Anthony


> Anthony Hannan <ajh18 at cornell.edu> wrote:
> > Daniel Vainsencher <danielv at netvision.net.il> wrote:
> > > Any insights on why these classes know so much
> > 
> > The general problem is lack of class extensions (traits), as you know.
> > 
> > > and how to fix it would be most welcome.
> > 
> > Here's an algorithm that will automatically extract a "minimal" package
> > given initial methods.  Its not the best for general factoring, which should
> > include more than the bare minimum, but its a start.  It utilizes traits/
> > multiple inheritance, but pseudo traits can be used.
> > 
> > 1. Associate each selector with the lowest common superclass of all
> > classes that implement it, but only if that superclass also implements
> > the selector itself.  If not, then put the selector in a new trait
> > shared by the highest subclasses that do implement it.  For example, the
> > selector #asSymbol has four implementors: String, Symbol, Character and
> > Vocabulary.  Since their lowest common superclass, Object, does not
> > implement #asSymbol, a new trait called CharacterOrStringOrVocabulary is
> > created (if not already created before for a similar selector) and
> > shared by String, Character, and Vocabulary.  #asSymbol is then added as
> > a selector in the trait with "self subclassResponsibility" as its
> > method.
> > 
> > 2. Create a new package.
> > 3. Add initial concrete classes that you want included, plus their
> > methods you want included (for this algorithm, a class means by itself
> > without its associated methods).
> > 
> > 4. Add concrete classes that package methods reference directly.
> > 5. Add selectors that package methods call.
> > 6. Add methods of selectors called that are in the hierarchy between
> > each selectors associated trait (from step 1) and each concrete class
> > already included.
> > 7. Go back to step 3 until no more new methods are add.
> > 
> > The result is a package containing all methods that can possibly be
> > called starting from the initial methods, without including selectors
> > and their methods that are never called, nor subclasses/superclasses
> > that are never used. 
> > 
> > #perform: is a problem.  Either you have to manually include all
> > selectors that can possibly be used by the particular performs included
> > in the package, or include all symbols as selectors if you know perform
> > selectors are not fabricated at runtime.
> > 
> > This algorithm also assumes instances will only be created from concrete
> > classes referenced.  If this is not the case, as in '(SomeClass allSubclasses
> > detect: [:cls | cls someCondition]) new', then they have to be added manually
> > as well.
> > 
> > Cheers,
> > Anthony



More information about the Squeak-dev mailing list