[Modules] Where do method removals go?
Allen Wirfs-Brock
Allen_Wirfs-Brock at Instantiations.com
Wed Aug 22 23:14:13 UTC 2001
IAt 02:16 PM 8/22/2001 -0700, Ned Konz wrote:
>On Wednesday 22 August 2001 01:02 pm, Allen Wirfs-Brock wrote:
>
> > Packages are code modules, they contain class, method, global variable, and
> > initialization definition. They do not have export, imports, or any other
> > sort of explicit dependency specifications. Basically, they just contain
> > code fragments.
>
>Much of the discussion I've read about modules seems to assume that loading a
>module is an exclusively additive process: that we are adding new classes
>and/or methods, or maybe changing existing methods.
>...
I think the best way to respond to this is to more fully explain how Team/V
works for the benefit of those who aren't familiar with it.
Every higher level Smalltalk language element (classes, methods, pools,
pool variables, global variables, class variables, initializers, etc. See
ANSI Smalltalk spec.) have declarative definitions. Packages are containers
of these definitions. In general, definitions can be arbitrarily
distributed among packages. In particular, the definitions of the
components that make up a class can be distributed across packages. This
allows the definition of packages that extend classes that are defined in
other packages. As I recall, Team/V didn't extend this to the level of
individual instance variable definitions, but I would certainly do so today.
Packages strictly partition the image. Every language element in the image,
must be defined by exactly one (loaded) package. The process of adding an
externally defined package to an image is called loading. Packages are
loaded (and unloaded) atomically. You either get everything in the package
loaded or nothing loaded. When you unload a package everything defined by
the package is removed.
If you attempt to load a package that defines a language element that is
already defined by another package in the image, a "conflict" is said to
exist and the load is aborted. There are various ways to resolve a conflict
which I'll get to in a moment, but first a little rationale. The motivation
for this model arose out of the experience of trying to maintain complex
systems using change sets (file-ins). All too many times, we experience the
problem where a change set would silently replace a method in another
"module" then later that module might either be filed-out with an
inappropriate method definition or other similar problems that I'm sure you
have all experienced. You can think about the "conflict" rule like
this. Assume that package A defines a method in Object like
dumbMethod
^"abc"
and that package B defines in Object a method like
dumbMethod
^"xyz"
This is a conflict. Which definition of dumbMethod should the system
use? Who can say? Presumably the builder of Package A thought that "^abc"
was the correction definition and similarly the builder of Package B
thought ^"xyz" was correct. Arbietrarily choosing either definition is
likely to introduce a "bug" that breaks code in the other package. So,
Team/V says, you can have package A loaded or package B loaded but not
both. However, it does provide tools for a programmer to resolve the conflict.
In this case, the programmer could load Package A, delete dumbMethod from
package A (implicitly creating a new version of A), and then load Package
B. Or, the programmer could load Package A, edit the unload Package B (the
tools support this) to delete the definition of dumbMethod, and then load
the new version of Package B. Alternatively, you could just tell the
package loader to load Package B and delete any conflicting methods. In
any case, you have to either created a new version of Package A or a new
version of Package B to resolve the conflict.
(Implicit in all this is an important version management concept. Once a
version of a module is "published" it must never be modified. It is
strictly read-only. You can derive a new version from the existing one but
you can not change the existing version and still retain its version identity.)
Because packages are containers of declarative definitions there is no need
to allow packages to contain removal definitions. If you don't want a
definition, you just don't include it in a package. In you are creating
Package C and in the process you decide that Packages B and C no longer
should contain a definition of dumbMethod, you simply create a new revision
of A and B without definitions of dumbMethod.
In this scheme there is still a possible role for change sets. In Team/V,
the development environment is completely scriptable. Everything you can
do in a tool you can also do in a script (the scripting language is
Smalltalk). It's quite possible, and occasionally useful, to create a
script that contains directives, to delete a method from a package, or to
rename a global variable, or to move a definition from one package to
another. Such a script is essentially a change set. The important
distinction is that it isn't a package but rather it is a set of
instructions for how to edit a package(s) to create a new version of the
package(s). Whether or nor the edits will produce the intended result is
dependent upon the version of the package(s) you start with matches the
assumptions of the person who created the script.
>It seems that this kind of pre/post load code would more properly belong
>in Allen's Clusters. The reason for this is that loading a given module into
>a system with other modules already loaded may require special customization
>for each of the other combinations of modules.
I hope I've provided enough background to make it clear why this is
unnecessary. If you are loading a package that requires specific versions
of other packages then you really should be loading a cluster that
identifies that those specific package versions. In Team/V the "migration"
from the previously loaded versions of those packages to the required
versions would be handled automatically based upon the declarative content
of the packages.
More information about the Squeak-dev
mailing list
|