[ENH][Modules] Delta Modules [was: Another version]

Allen Wirfs-Brock Allen_Wirfs-Brock at Instantiations.com
Tue Oct 23 17:14:21 UTC 2001


At 09:45 AM 10/23/2001 +0100, goran.hultgren at bluefish.se wrote:
>...
>Object subclass: #Module
>   instanceVariableNames: 'version parentModule neighborModules
>definedNames exportedNames repository'
>  ...

This apparently defines the class that is used to model a "module" that is 
loaded into an image. More interesting would be a specification of a 
"module" that was external to an image.  (After all, by the time you've 
loaded a module all the interesting work has already happened). For 
example, I'm guessing most or all of the above instance variables reference 
other instantiated meta objects of the module system. How do those 
translate externally?.  What is the external form of a module reference. 
Externally, is definedNames a list of class and global names or is it the 
actual source/object code for the defined entities. How about exported 
names. Is it a list of strings?

>...
>- Submodule = Another module that is one of my children. Consider it a
>"part of me". Especially note that a submodule of "me" has me as it's
>parent. This is in contrast to the external modules whose parent is
>someone else completely.

Note that the bi-directional linkage of submodules and parents mean that a 
particular module may be a submodule of exactly one parent.. This would 
seem to significantly limit the reusability of modules. This is 
particularly a problem if you think about your modules in a context 
external to an image. In concept a "module" could contain code that is 
applicable in many different situations by many different parents but the 
tight (and early) binding of the submodule to the parent means that to 
reuse the code it will have to be duplicated within additional modules.

>- Module parameter = Well, perhaps it sounds better if we call these
>"parameter module" instead. It is an advanced feature that means that
>the module shas a "valueholder" instead of a reference to a concrete
>module. We then have to specify a concrete module as a value when we
>load (or perhaps activate?) the module in question. An example would be
>to make stuff "pluggable" so that for example you could bind another
>"Transcript" than the standard one etc.

How would you externally represent a such a set of module bindings so it 
can be reproducibly loaded.  You don't want to depend upon "doIts" for 
this. Don't you need some sort of configuration module to specify these 
bindings?

>- Delta module = Yes, we have discussed these in length. When going home
>on the train last night I saw them even more clearly than before. Let me
>explain:
>
>If we build a module with everything in it (classes and loose methods
>end tutti) in a big pile we have a problem. The classes are self
>contained, they are what they are and do not need any more information
>to be "complete". But the loose methods (read class extensions) need a
>"home". Ok, so we have to say what class they should go into. But then
>we are still not clearly defined because - what version of that class
>are we referring to? We need to say "this loose method should go into
>class Object version 1.34" to clearly define things. So our "loose
>changes" to classes outside of our own module needs to be complemented
>with information about the version of those classes that they refer to,
>right? Aha! This is exactly what the Delta modules do! They group our
>"loose changes" that should be applied to classes in other modules and
>complement them with information about which specific module they should
>be applied to.

No, this is wrong!  You are binding too early and hence limiting 
reusability. Consider the classic class extension, adding a isFoo method to 
Object. In most cases, the extension module that defines this does not care 
which version of Object it is extending. The same extension module should 
be usable  by many parent modules.  When assembling a system you will want 
to bind an extension to a particular parent, but not any earlier.

An overly constrained module system is essentially the same as no module 
system. If every module must explicitly identify the specific versions of 
other modules it interacts with then you have essentially gone back to 
having a monolithic image where any change causes a cascade of dependent 
changes throughout the system.

...
>- One thing that might confuse people is that when Henrik (and I) says
>"module" he means an exact version of a bunch of code. This means that
>"Morphic 1.23" is ONE module and "Morphic 1.24" is ANOTHER module. In
>ordinary speech we sometimes talk about "the module Morphic" talking
>about all/any version of that stuff. This is a naming problem and
>perhaps there is a better word for "Module" that we should use... A
>deltamodule is always in reference to a specific module, for example
>"Morphic 1.23". So when a module has been "published" it should never
>ever change content of course.

Most systems would make a terminology distinction between a logical module 
and a particular "version" of the module. Common terminology would be 
"module version", "module revision", "module edition", etc. It's would 
certainly help communications, to choose a term and then to be fastidious 
in making the distinction.


>- A Deltamodule inherits from Module and this could perhaps be
>refactored with a common baseclass as is common in the Composite pattern
>but I haven't looked into that issue. One fact though: Looking at the
>code a Deltamodule CAN NOT have neighborModules. Those methods are
>overridden. So, a Delta module can only be a leaf in the Module tree.
>Henrik, what about applying the Composite pattern here? Or are there
>other considerations?

Why the restriction on neighborModules?  This would seem to imply that a 
class extension may not reference any classes (or globals) that are not 
already known to the parent. This would seem to extreme limit the use of 
deltamodules.


>...
> > Eh, well since a Deltamodule defines a difference between two modules it
> > should be able to contain a whole new class. But you would probably
> > rather seldomly have one Module add classes to another module so it will
> > probably be a rare case.
> >

Again, this seems like the common case, not the rare case.  The module that 
defines the Foo class also wants to add the isFoo method to Object and 
possibly other classes.

>...
>Ok, so revising it a bit further (leaving out module parameters):
>
>- A Module contains global definitions including classes and can contain
>other modules and Delta modules creating a tree.

As explained above, it's not a tree -- it a cyclic graph!


>- A Delta module can only be a leaf in the module tree and defines the
>difference between two Modules. (changed methods, added methods, added
>classes, removed methods or
>  classes etc.)

So to create a delta module you first must have two "editions" of a module 
and the creation process creates a third edition of the module (necessary 
to contain the child extension reference) plus an extension module?


>...
>Obviously the Delta modules are the tricky part - but personally I just
>view them as a "diff" between two modules. I do have a question to
>Henrik though - the deltamodule refers to the baseModule that is applies
>to but it doesn't refer to the resulting module when it has been
>applied. Ok, I admin that the last sentence sounded strange, but let me
>put it like this: When Delta module Z has been applied to "Morphic 1.23"
>I can't really say if the result is "Morphic 1.24" or whatever? The
>source is defined but the target is not. So... I am not even sure if
>that is a problem, but perhaps it can be? When it comes to conflict
>detection I mean. Whatever...

Since I've been throwing stone I should also offer a solution.  I think 
what you need to decouple extensions and parents.  You can do this by 
introducing a new module type, call it an extended module. So, instead of 
defining Module "Morphic 1.23" that must explicitly include module "Z 4.56" 
(and which must explicitly say it extends "Morphic 1.23") it would define 
the extended module "MorphicWithZ 1.0" which includes as children "Morphic 
1.23" and "Z 4.56"

>...
>regards, Göran

Final thoughts.  I would expect a module system to support two major goals:
         1) Reusability of modules
         2) Reproducability of system configurations.

These goals might appear to be conflicting but need not be. However, you 
have to be very careful in designing a module system to not achieve one of 
the goals at the expense of the other. My sense is that the design 
decisions in this system that support goal 2 will severely interfere with 
goal 1.

Allen





More information about the Squeak-dev mailing list