[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