[m-dev.] module system discussion
Fergus Henderson
fjh at cs.mu.OZ.AU
Mon Nov 19 17:53:33 AEDT 2001
After the Mercury meeting today, we had a discussion of the various
module system proposals that have been floating around. I will attempt
to summarize this discussion.
First, let me start by explaining the problems that these proposals are
trying to address. There are in fact a number of different problems:
1. The namespace (or "open module") problem.
Mercury uses nested modules for namespace control:
if you have a bunch of modules that are all logically related,
you make them sub-modules of a parent module, and then all of
the names in those sub-modules are prefixed with the name of
the parent module.
However, this requires that you know in advance the set of
sub-modules. If you later decide that you want to add an
additional one, then you need to modify the source of the
parent module (to add an explicit `:- include_module'
declaration for the new sub-module).
Sometimes it would be nice to group a set of modules into
a single name space, but without fixing that set of modules
in advance, and without requiring the parent module to be
modified and recompiled when you add a new child module.
In other words, modules in Mercury are always "closed"
rather than "open". This is OK when modules are used to
encapsulate individual source files, but when they are used
for packaging, it can be desirable to have some way of
defining modules that are open for extension by the addition
of new sub-modules.
The lack of support for this causes particular problems when
interfacing with other languages that do have support for this
(e.g. via "packages" or "namespaces").
The concensus on this issue seemed to be that it would be a good
idea to add some support for doing this kind of thing in Mercury.
We didn't discuss what form that support would take.
2. The "late binding" problem.
Mercury's module system is based on the idea of each module
having an interface and a single implementation. But sometimes
you may want to have multiple implementations, and to be able to
delay the time when the system determines which implementation
a name refers to, so that that decision is made only at run time,
link time, or compile time, rather than when the source is written.
This issue is related to the issue of assembly qualification for .NET.
But I'm not sure if I really understand what the problems are there.
My position on this issue was that Mercury supports late binding
through the type class system, and so it would probably not be a
good idea to try to solve this using the module system. Hence I was
not in favour of language extensions here.
3. The "zillion imports" problem.
Peter Ross has complained about needing too many `:- use_module'
or `:- import_module' declarations when interfacing with the
Mercury modules generated by our .NET component interface
generator tool.
4. The overloading problem.
In cases like extras/complex_numbers, sub-modules are used just because
Mercury has some restrictions on overloading things with the same
name and arity in a single module. Conceptually you really have a
single entity; it is broken into sub-modules only because this is
needed to allow overloading.
In this situation, it would be nice to make things easier for users
of such modules, so that they could treat it as a single entity,
rather than needing to explicitly import all the sub-modules.
(It would also be nice to make things easier when defining such
modules; but unfortunately doing that would have some significant
drawbacks that I've explained in an earlier mail. So I don't think
that is worth it.)
5. The repackaging problem.
Sometimes you have a collection of third-party libraries that you
want to repackage together as a single meta-library.
Next, I'll discuss the proposed solutions.
S0. The status quo.
Problem 5 can be handled in a couple of different ways using
the existing support in the language. But each of these
does have some significant drawbacks:
(a) Using explicit forwarding.
This requires duplicating the interface of the
modules that are being repackaged, which leads to
a double-maintenance problem.
There are also some difficulties with forwarding
typeclasses and constructors.
For constructors, to handle that properly we'd
probably need something like "views" -- this has
been discussed previously and is probably a good
idea anyway, regardless of what happens with the
module system.
For typeclasses, you can define a derived typeclass
that adds no new methods, but this requires additional instance
declarations for the new typeclass. Perhaps it would
be worth providing a renaming mechanism for type classes,
like we have for types, insts, and modes.
(b) Using `:- include_module'.
One drawback with this approach is that you need to
recompile the third-party libraries to make them part
of the parent module for the meta-library.
Another drawback is that the `:- import_module'
declarations in the third-party libraries need
to be modified so that they include the prefix
for the parent library.
Another drawback is that if you have some components
in your program which use the third-party libraries
directly, and some which use the repackaged version,
then you'll end up with two copies in your executable.
On the other hand, perhaps problem (5) is not one that occurs
often enough to be worth worrying about; these existing solutions
may be sufficient, despite their drawbacks.
S1. `:- auto_import'.
There's a new declaration `:- auto_import <Modules>',
where <Modules> is a list of fully-qualified module name.
This may only occur in the interface section, not in the
implementation section. The effect is that if this
declaration occurs in the interface for module foo,
then any `:- import_module' or `:- use_module declaration'
for `foo' is treated as if there was also a corresponding
`:- import_module' or `:- use_module' declaration for
the <Modules> specified in the `:- auto_import' declaration.
For example, if you have the following two modules,
:- module m1.
:- interface.
:- auto_import m2, m3.
:- end_module m1.
:- module m4.
:- interface.
:- use_module m1.
...
:- end_module m4.
this would be equivalent to
:- module m1.
:- interface.
:- end_module m1.
:- module m4.
:- interface.
:- use_module m1.
:- use_module m2, m3.
...
:- end_module m4.
This implies that entities in modules m2 and m3
can be referred to
A variation on this proposal, which I will call S1 (b),
is that there is a further restriction that the <Modules>
listed in an `:- auto_include' declaration are only allowed
to be sub-modules of the module in which the `:- auto_include'
declaration occurs.
This proposal would provide a solution to problems 3 ("zillion imports")
and 4 ("overloading") above.
S2. `:- include'.
There's a new declaration `:- include <Modules>',
where <Modules> is a list of fully-qualified module name.
This may only occur in either the interface or implementation
section. The effect is that the entities declared in the
interfaces of the specified <Modules>, or *included* (directly
or indirectly) in those interfaces, are *included* in the
corresponding section of the containing module,
which means that they can be referred to as
if they were members of that section of the containing module.
(By "the containing module", I mean the module in which the
`:- include' declaration occurs.)
Apart from that, all the usual rules in the Mercury language
reference manual apply.
Note that since the entities are only *included* in the
containing module, rather than being *defined* in the containing
module, the prohibition against defining multiple entities in
a single module with the same kind (pred/func/type/etc.), name,
and arity does not apply.
This proposal would probide a solution to problems 3 ("zillion imports"),
4 ("overloading"), and 5 ("repackaging") above.
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list