[ENH][Modules] Delta Modules [was: Another version]
Allen Wirfs-Brock
Allen_Wirfs-Brock at Instantiations.com
Wed Oct 24 18:46:37 UTC 2001
At 12:34 PM 10/24/2001 +0100, goran.hultgren at bluefish.se wrote:
>...
>Allen Wirfs-Brock <Allen_Wirfs-Brock at Instantiations.com> wrote:
> > At 09:45 AM 10/23/2001 +0100, goran.hultgren at bluefish.se wrote:
> > >...
> > ...
> > 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?
>
>Ehrm. I have no good picture of this unfortunately! I hope Henrik chimes
>in.
>Have you got his code by the way? I can always give you an url with the
>image we used at OOPSLA.
Actually, I've been kind of avoiding using the code as a reference.
Facilities like this should be explained and understandable without
reference to source code. Otherwise it is impossible to separate the
specification from the implementation details.
> > >...
> > >- 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.
>
>Well, I think I say yes and no, or something... :-)
>
>Yes, each module has only one parent. The full name of the module is
>derived from its place in the module hierarchy. And yes, that is a tree
>which means a submodule only really lives in one single place.
>(Sidenote: I like this. This is simple. More or less like in Java btw. A
>module has a home and a name. Period.)
Wait...Java module? Do you mean Java packages? I wouldn't characterize
Java packages as "modules", they are a name space mechanism. They simply
provide a hierarchical naming scheme. However, packages have no physical
manifestation in Java. There is no entity you can point at and say this is
the package com.instantiations.jove. You can't even enumerate all the class
that are defined in that package because it is an open ended set. All you
can do, is for any particular class answer the question, "Is this class
defined in the package com.instantiations.jove?"
Take a class such as Parser, defined in the package
com.instantiations.jove. It's real name is
com.instantiations.jove.Parser. All Java packages do is provide a lexical
scope where that name can be abbreviated to its shorter form Parser.
There has been a lot of discussion (and little agreement??) on this list
about what we mean by a "module". Cutting through the nuisances I suspect
that most people could accept the following: A module is an *atomic* unit
of functionality (code, objects, whatever) with an independent existence
that can be incorporated into a program (image, whatever). The atomisity
aspect is very important. If loading a module, the normal expectation is
that you get the whole thing.
From this perspective, a Java package is clearly not a "module". The only
things in Java that fully match this definition are classes although an
argument could also be made to consider Java "compilation units" (source
files) as modules.
To wrap up this train of thought, lets revisit
com.instantiations.jove.Parser. There isn't a single instance of the com
or the com.instantiatiuons or even the com.instantiations.jove package
where this class lives. There can be many different compositions of these
packages some, but not all, of which contain Parser.
>BUT... you can also "link" modules as an external module - didn't I
>write that? Yes I did. But perhaps it wasn't clear. Or perhaps I am dead
>wrong. Henrik, correct me here but wasn't the idea that if a module
>needs to reuse an already existant module placed somewhere else
>completely in the module tree it just references it as an external
>module? I think so.
Perhaps, I guess this is where some of the complexity leads to confusion.
Is there really the need for both external modules and submodules and
module parameters. Are their usages truly orthogonal? Will user's know
when to choose one over the other? Couldn't this be simplified?
Regardless, you have clarified one thing for me. Apparently, there is a
module definition tree (with parent back pointers) and a module usage
(dependence) graph.
>...
>
> >
> > 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.
>
>Ok, I see your argument. But... Hmm. The Debian package system is very
>early/tight bound and it sure doesn't mean it is useless... Anyway, I
>think I will pass on this one and let Henrik dive in! :-)
>
>I need that watch that Tim Olsen (name?) has in Superman...
I think his name is Jimmy
>...
> > 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.
>
>Ok, I like "module revision" or "module version". In the Smalltalk world
>the word "edition" and "version" might be tainted by earlier products in
>such a way that we should perhaps stay clear of them. And the word
>"revision" is used in CVS but the meaning there is probably intuitive
>enough to not be a problem.
>
>I vote for "module revision" meaning "one specific version".
>And when we say only "module" we should always mean the logical module.
>
>Agreed? :-) (pretty, pretty please...)
fine with me...
>Perhaps we should then rename those classes to ModuleRevision etc...
>
> > >- 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.
>
>Ah, I checked the code! :-) Well, a Deltamodule can not HAVE neighbors,
>instead it defines CHANGES to it's basemodules neighbors. So I think
>your guessed implication is not valid. Phew. :-)
Wait, not so fast. Does the set of possible "changes" include the addition
of a new neighbor? If not, you still have the problem. Regardless, I think
you may be adding unnecessary conceptual complexity.
Here's a sketch of what I think of as a prototypical "module" when I
consider things like this:
module "FooImplementation"
extends class Object with method isFoo
implements class Foo with assorted methods
references class Bar (defined in another module)
To me, this is a nice self-contained unit. Why would I want to be thinking
about changing the definition of the module that defines Object. It's not
necessary in order to implement the above. It also would have a broader
effect then I intend. If Object's module now essentially imports Bar (or
Bar's module) as a neighbor then presumably this has the side-effect that
its other submodules of Object's module could also reference Bar. (As a
side point, I also don't really want to think about which module implements
Bar)
A possible reason for this difference in perspective just occurred to
me. Most of the Squeak modularity discussion has been in the context of
"modularizing" the existing Squeak image. In other words, taking what's
there and chopping it up into a set of modules. If you are looking at the
problem from that perspective it's easy to think of the one definitive
structure of modules that define the current system and to tightly bind
them so you are guaranteed to have the same composition that you currently
have in the image. However, that's really isn't the important perspective
going forward. You need to be able to define new modules that will be
composed in many different ways in different situations to assemble a wide
variety applications. It's really all about reusability. You need to be
able to reuse your modules in unanticipated ways. This means you have to
be very careful about premature or unnecessary bindings.
Like I said in the previous message. If all the modules that make up the
current image are tightly bound you are no better off then you are today.
> > >...
> > > > 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.
>
>Really? When you write "and possibly other classes." did you mean "and
>add possibly other classes." or "add the isFoo method to possibly other
>classes."?
I meant extend other classes but certainly you might need to also define
additional classes. I specified my canonical test case above. Everything
else is pretty much an elaboration of one of the three concepts I used in
FooImplementation
>It doesn't seem common to me that the module Morphic typically would add
>classes to the module Collections (or any other module), methods
>certainly probably all over the place but new classes in OTHER modules?
>Don't really buy that. Convince me! :-)
No, I didn't mean "add a class to the Collection module". However, a
method extension to a Collection class certainly might reference a class
that was not currently a neighbor of the Collection module.
> > >...
> > >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!
>
>Yes, my threeliner tried to be "pedagogic" in the sense that the first
>line establish the module tree and then I add the fact that there are
>also crossreferences making it somewhat "graphish", but still - those
>references are notably different.
As I mentioned above, it appears to me that there are really two overlayed
structures. A definitional tree and a dependency graph.
>Perhaps we should try to revise the threeliner even further then
>(leaving out "module parameters" and changing "module" to "module
>revision"):
>
>- A Module revision contains global definitions including classes and
>can contain
>other module revisions and Delta module revisions creating a tree.
Clarifying the meaning of the word "contain" in this context is probably
important.
>- A Delta module revision can only be a leaf in the module revision tree
>and defines the
>difference between two Module revisions. (changed methods, added
>methods, added
>classes, removed methods or classes etc.)
>
>- A Module revision also references so called external module revisions
>(used module revisions) outside
>of it's subtree. This enables reuse of module revisions across module
>revision tree boundaries. This actually turns our simple tree into a
>cyclic graph but do note that a module revision still only has one home
>(=one parent module revision) in the tree.
So what if I need to define a module like this:
module "FooImplementation2"
extends class Object with method isFoo
extends class Collection with method asFoo
implements class Foo with assorted methods
references class Bar (defined in another module)
and Object and Collection are defined in two different modules (note I
didn't use the term "module revision" , at this level of abstraction I
don't really care about specific revisions). It sounds like this extension
would be impossible to define because it would be a delta module that would
require two parents. A similar problem would occur if I started with a
parent that defined two classes, created a delta module, and then I decided
I really needed to break the parent into two separate modules.
Again, my one over-riding message is that for reusability you need to defer
binding decisions as late as possible.
>...
> > >- 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?
>
>I think you lost me there. As it is meant to work now (I think) is that
>when you change a class in a different module than your "own" (that you
>are working in - think "current module" like in "current changeset") a
>delta module revision is created and added to your own module revision.
>Any other changes after that in that same other module will also end up
>collected in this delta module revision.
I pushing to see if you really meant what you seemed to be saying. Module
revisions are presumably real entities. You could store them externally,
compare them, etc. "defines the difference between two Module revisions"
says that you have two distinct module revisions already in hand. I don't
think this is really what you meant.
To be more concrete, you statement seems to say that if (and only if) I
have module revisions BazImplementation 1.0 and BazImplementation 2.0 then
I can create a delta module DeltaBaz 12.0 that captures the difference
between them. The semantics of delta modules (as I understand them) would
also require the creation of BazImplemention 1.1 that explicitly lists
DeltaBaz 12.0 as a child. BazImplemention 1.1 would then be functionally
equivalent to BazImplementation 2.0.
I think what you really mean, is that you can start with just
BazImplementation 1.0 and instead of creating BazImplementation 2.0 to add
a new method you can create BazImplemention 1.1 and DeltaBaz 12.0.
Because of the fact that intermodule reference are always references to
specific module revisions, BazImplemention 1.1+DeltaBaz 12.0 is still not
precisely equivalent to BazImplementation 2.0. You would have to
explicitly reference one or the other (premature binding!)
>This delta module revision is also (mostly I guess) activated from the
>start meaning that the method just added is actually there able to run.
>
>This was probably not an answer to your question...
While the manner in which modules are dynamically constructed is important
in building a good tool set, it shouldn't be necessary to think about
dynamic construction in order to understand the semantics of the module
system. It's quite likely that the tools for dynamic module construction
may require modules to pass through "illegal" or incomplete states. This
is analogous to filing-in a change set with forward reference. You may
temporarily have Undeclared bindings but they will go away eventually.
> >
> > >...
> > >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"
>
>I am sorry, my brain is turning into jello here. I can't give any
>sensible response.
>
>But I can try to clarify my little question:
>
>Currently a delta module revision exactly specifies a new revision of
>another module revision.
>It does this effectively by definining a bunch of differences that
>should be applied to the specifically named module revision. So... delta
>module revision "Z 1.0", which is actually my improved homehacked
>version of "Morphic 1.23" includes a reference to "Morphic 1.23" and
>then a bunch of changed methods, added methods etc.
>
>Loading and activating "Z 1.0" will also load and activate "Morphic
>1.23" and then apply all those changes to it.
>
>Now, back to my question: What is now the activated revision of Morphic
>called? It is not 1.23. And the delta module doesn't say. It's like an
>"open edition" in ENVY (or whatever they are called) that hasn't got a
>revision number yet. And more importantly - is this a problem? Perhaps
>it's just fine, I can't see the implications.
Well I think those are all good questions that I think reinforce the point
that you don't really man that a delta module just capture the deference
between two pre-existing module revisions.
> > >...
> > >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.
>
>Well, let us bounce this around a bit first and let Henrik explain it a
>bit further - my impression is that he has given all this a lot of
>thought and also read up on the problems too. He has also studied Ginzu
>in some extent. So I have faith that it isn't as "bad" as it looks when
>I try to explain it! :-)
As should be clear by now, it's the premature bindings that concern me.
Thanks for the interaction. I like it.
Allen
More information about the Squeak-dev
mailing list
|