I have been out of town for a few days without email, this is why I haven't been able to answer before.
Andrew P. Black wrote:
DeltaModules are a kind of Module[2]. They are distinguished from base modules by being defined by difference. ... So, my question is: why do you consider DelatModules as being conceptually different from Modules at all? Why do they have different properties, just because they happen to have a different representation? ... Why do DeltaModules and Module not have identical protocols? Why are DeltaModules and regular Modules not just tow implementation classes with the same interface?
You are right: My specification of DMs was unclear as well as unfinished, but I wanted to put it out early along with the code.
It did mix the implementation aspect with how DMs would be used, in the manner of "here are some problems, and this is how DMs can address them". The implementation difference is not strictly linked to the uses I mentioned, but in practice there will be such a link: the convenience of the delta representation means that class extensions probably will be put in DMs 99% of the time, and so on. But I know it may have looked like there was a harder link there. (I hope this answered your policy vs. mechanism point as well, otherwise let me know.)
You are also right in that the differences between regular and delta modules should be as small as possible, and that we should be specific about what they are. However, the two cannot be identical: a DM needs to be defined relative to a base module, and the concept of a base module is meaningless for a regular module. This ought to be the only real difference. Then we may want to have some tool-like support for viewing DMs in terms of differences wrt the base module, but those are minor issues.
I think that this situation between Modules and DeltaModules is rather common in class/subclass relations, and I think your question can be understood by analogy to other known cases: why aren't the protocols for Array and OrderedCollection identical, and so on. It is because they are very similar but still slightly different.
The result of activating/installing a DM is equivalent to creating a new/different version of the base module by filing in all the contents as a regular Module. (I now think that de/activating a DM is a better term than un/installing it.) You aren't forced to use DMs for class extensions, but filing in five new methods is clearly more convenient than loading a new version of the whole module that contains String.
Activating a DeltaModule does not modify its base module--it creates a new version of the base module, with the modifications installed. Being able to modify a module is a bad thing since different code packages should be able to specify a module by version and be able to rely on its contents. But this distinction is a technical detail.
ducasse stephane wrote:
I have mod1 with extensions (DM1) = String>>asUrl
can I see String>>asUrl from mod2 if there are not relations between the two?
I have the intuition that I should only see asUrl from a module only if this module depends from mod1.
What is your point of view on that?
There is a short answer to this: Yes, that was just how I intended it to be.
More precisely, when the DeltaModule containing your extensions would be made active, this would create a new, modified version of the base module with the changes installed into it. If mod2 wouldn't specify a particular version of the modified module, then it might use the new version as well, but if it specifically wanted the old version then it wouldn't see the changes.
If two different loaded systems want to modify the same module (the same class/es), then you need to switch between the two module versions created by the modifications--you enter into the area of conflict resolution.
Andrew P. Black wrote:
I understand that "DeltaModules can be un/installed, but the un/install operation has no meaning for regular Modules" [1]. My question is: Why. If un/install is such a good idea, why not have it for all Modules, not just for DeltaModules?
The reason is that Modules are independent and self-contained, and therefore cannot be in conflict with each other. However, several packages may want to apply DMs to the same module, and then there is a use for being able to de/activate all but one of these DMs.
But while you could have two versions of Morphic loaded at the same time, with no conflicts since they would be two different modules, you can't have both running at the same time. E.g. who takes care of input events? But this is not a conflict on a module level (which just defines code), but on a component level (i.e. between parts of the system that are running).
I just put my "loose methods" (like String >> asUrl) into a DeltaModule inside my Module, and the unsuspecting user who imports my module is still surprised that it "damages" other classes like String, or Form, or whatever.
I don't agree at all. DMs not only collect all external modifications in a special place, instead of mixing it with the "proper" contents of your module. They also associate such modifications with the modules where they are made, so that you by looking at the list of delta modules can see exactly what parts of the system a certain package modifies. Any "unsuspecting user" would most probably look at what parts of the system a module modifies before they use it. In this way this is made easy. Can you suggest any way to make it clearer?
This also serves to make it very clear to a conflict resolver in what parts of the system conflicts arise with other loaded packages: conflicts need only be handled in those modules where multiple sources want to have modified versions of the same module.
Now, I had assumed up until this morning that a Module could contain not only whole classes, but also "class extensions", that is, groups of methods that could be added to existing classes, even though those classes might be defined in different modules. (The String>>asUrl example again, which I had assumed could be part of the HTML module).
But the very purpose of modularity is to separate a system into smaller, independent, self-contained pieces, whose definitions are not entangled in each other. Modules really should not be allowed to modify the contents of other modules. Allowing this would go against the very idea of modularity--it is really a contradition in terms, more or less. It is the same violation as if an object would be allowed to directly alter the innards of another object, it breaks encapsulation.
A module
- will of course also have contents proper: classes, globals, etc.
I notice that "proper contents" does not include methods. Is this intentional? Is this a mechanism restriction that is intended to make it hard for me to put the "wrong stuff" in my module, that is, to put in "loose methods" that change some other classes?
...
If so, I admire your good intentions, but I think that you are misguided.
This is just because in ordinary Smalltalk you don't put methods anywhere except as part of classes, this just follows that principle. You may consider Smalltalk to be misguided when it enforces this principle, and would then regard C++ as superior in this respect, but many would consider this part of the essence and elegance of Smalltalk. #Smalltalk contains classes and other globals, but not loose methods, it's the same thing with modules. In fact, neither DMs contain loose methods, they are put in class objects too, at least as it is now. In fact it would be more work to support the kind of exception you suggest, than to simply put methods in classes like now.
Dan stated earlier that while method extensions may be supported, they shouldn't be encouraged (something to that effect), and I agree, since it breaks the above principles. I see it as a kind of emergency solution or exception, a concession to realities, it is never strictly necessary I believe--although I don't want to repeat the {} discussion here.
Now I see that I might be wrong about this, and that Andreas' point of view would say that Modules shall contain _only_ whole classes, and DeltaModules shall contain _only_ class extensions and perhaps class retractions (deleting methods).
Since DMs are defined as differences in relation to a base module, per this definition (and for superseding change sets) they strictly ought to be able to define any possible differences in a module, however some changes are harder to support than others. Still, adding new classes should definitely be possible, and it is easy to support (DMs being Modules, I think they already do). But this would probably be used when DMs are used in the role of change sets--a package will rarely need new classes to be added to other modules.
The email of yours in reply to Michael Rueger also said a lot of interesting things about modules being namespaces (not stated on the Wiki) and that these namespaces do not follow the hierarchic structure of the module nesting (not on the Wiki either).
In both cases, the information on how names are looked up was in the first posting I made, and was copied into the first heading listed on the Swiki, "design principles". However, Smalltalk is the only language I can think of where different modules share a single namespace, so I may not have made it as clear, taking it for granted. Again, it seems to go against the very principle of modularity, where modules' contents should be independent per definition. So I've been taking this feature for granted whereas all Smalltalkers obviously don't.
The distinction between BasicModules (as I shall call them) and DelatModules as I now understand it is:
As I said above, it now seems clearer that the only difference ought to be that a Module is self-contained, whereas DeltaModules are represented as differences wrt a base module. However, this apparently small difference will lead to great differences in usage patterns.
- BasicModules can be used only to define whole classes, whereas
DeltaModules can be used only make additions, removals or changes to classes that are defined elsewhere.
Regular Modules should be complete and self-contained, as per the definition of modularity, with e.g. complete classes, as usual in Smalltalk.
DMs should in principle be able to handle all possible differences wrt a base module: new items, deletions, and changes.
- BasicModules can contain (sub) BasicModules, global specifications
and Class specifications, but not DeltaModules.
Regular Modules can be linked to any other Module, regardless of their kind (of course). PackageModules etc. are unnecessary.
- DelataModules can contain (sub) DeltaModules and change
specifications (but not BasicModules)
A DM really ought to only specify changes to the contents, and not itself have any submodules. If your system X modifies module A and A's submodule B, then X should have one delta module DM(A) and one DM(B), this is for clarity, in this way you clearly see what parts X needs to modify.
Henrik