[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
|