Hi!
Talking to a friend, who is project manager in a software company, about
modules for Haskell, he made two comments that may be of interest to the
current discussion.
(1) With regard to the idea of 99% hand-written interfaces (just mark everthing
that should go into the interface in a combined interface/implementation
file) that I proposed and that was supported by Peter, my friend pointed
out that this could make multiple implementations for one interface a bit
more labour. You basically have to guarantee that the interfaces extracted
out of the combined file for version one and version two of the
implementation are equal, i.e., the interface is duplicated in both
versions.
Still, I find this less onerous than having a separate implementation and
interface for three reasons: (1) the common case is one implementation for
one interface (better shift the labour to the occasional case); (2) in the
Modula-2 style there is also some duplication of code (procedure/function
signatures); and (3) in the case of two implementations for one interface
you have to deal with issues of consistency between the versions anyway.
(2) He pointed out that it is desirable to be able to restrict the access to
some modules in a way that the compiler can control when a group of people
is working in one module hierarchy. Too illustrate this, assume that we
classify the modules into different levels of abstraction, say, three
levels:
level 3 modules
|
v
level 2 modules
|
v
level 1 modules
Now the modules in level 2 may use the modules from level 1; the modules
from level 3 may use the modules from level 2, but *not* the modules from
level 1---I think it is clear that such a case is rather frequent. Such
access control may be easy to achieve when it is possible to deny the
people working on level 3 the access to the interfaces of level 1 (e.g.,
don't copy them the interface or use UNIX file permissions). But this may
often not be possible, for instance because some people are working at
modules in level 2 and 3. So, we like to have some way to specify that the
compiler simply does not allow to import (directly) modules from level 1
within modules from level 3.
Actually, C++ has a rather ad-hoc solution (are you suprised?) to this
problem, the `friends'. An object may be friend of another object; then,
that object can access (private) fields that are not visible to other
non-friend objects. The problem here is that the object providing some
service has to specify all its friends, by name. If it is required to add a
new friend, the used object has to be changed. Consider, in our example
hierarchy, that you want to split some existing level 2 module into two
modules; using friends, this requires to change modules in level 1, which
is obviously bad.
Now, what about the following idea? Each module is element of a module
category. Such categories are named and each module states to which
category it belongs. Furthermore, a module lists all categories of which
the members may import it. In the example, we have three categories, say,
Level1, Level2, and Level3. All modules from Level1 allow to be imported
from Level2, and all modules from Level2 allow to be imported from
Level3. This pervents imports of modules of category Level1 from modules in
category Level3, and is easy to check for the compiler. Splitting a module
does not require any changes in underlying categories.
Cheers,
Manuel