[mercury-users] Modules, Submodules and Instances.

Fergus Henderson fjh at cs.mu.OZ.AU
Sun Jan 31 09:50:52 AEDT 1999


On 30-Jan-1999, Ralph Becket <rwab1 at cam.sri.com> wrote:
> Fergus Henderson wrote on 30 Jan:
> > 
> > > What exactly is the naming convention here?  Under 0.8.1 I take it
> > > that bar and baz must be implemented in files foo.bar.m and foo.baz.m
> > > respectively.
> > 
> > That's correct.
> 
> That's interesting, because
> mercury-extras-0.8/complex_numbers/complex_numbers.m has the following
> body:
> 
> 	:- module complex_numbers.
> 	:- interface.
> 	:- include_module complex, imag.
> 	:- include_module complex_imag, imag_complex.
> 	:- include_module float_imag, imag_float.
> 
> but the modules imag etc. are all defined in files imag.m etc.  I
> gather that complex_numbers.m is used in libarary generation?  Is this
> a convenient abuse of the include_module directive or is something
> deeper going on here?

Oops, sorry -- what I wrote was *not* correct.

The correct answer is documented in the "Using the Mercury compiler"
chapter of the Mercury user's guide:

|   Arguments to `mmc' may be either file names (ending in `.m'), or
|   module names.  For a module name such as `foo.bar.baz', the compiler
|   will look for the source in files `foo.bar.baz.m', `bar.baz.m', and
|   `baz.m', in that order.

One point that is not documented there is that you must use a fully qualified
name for either the file name, or the module name in the `:- module'
declaration, or both.

Unfortunately there are a few other places in the documentation where
file naming conventions are mentioned, and they were not updated when
this change (to allow non-fully-qualified file names if the module
name in the `:- module' declaration is fully-qualified) was made.

Thanks for letting us know about that -- I will modify the documentation
to fix the points mentioned in the previous two paragraphs.

> > > (3.2) Does it matter where the include_module declaration goes?
> > > Is there any difference between placing it in the interface or the
> > > implementation section?
> > 
> > Yes, there is a difference.  If you put the "include_module" declaration
> > in the implementation section, then that sub-module will be private;
> > it can only be used by its parent module and by other sub-modules
> > of the parent module.
> 
> I'm slightly confused here.  I was under the impression that
> include_module only declares a module to be a sub-module.  The
> name-space, however, is actually extended by use_/import_module.

That's correct.

The placement of the `include_module' declaration affects the access
(public/private), but not the visibility.  To make something visible,
that something needs to be accessible, and you also need to use
a use_/import_module declaration.

> Consider
> 
> 	:- module foo.
> 	:- interface.
> 	:-	include_module foo__bar.
> 			% At this point, we only know that foo__bar
> 			% is a sub-module, we don't have access to
> 			% its interface.

I think you may be confusing access (i.e. permission) with visibility
here.  Both `foo' and modules which import `foo' do have permission to
access the interface to `foo__bar'.  However, the declarations in
`foo__bar' are not yet visible, since you haven't given a `use_module'
or `import_module' declaration for `foo__bar'.

> If foo's interface goes on to to say
> 
> 	:-	import_module foo__bar.
> 			% Now foo__bar's interface is part of foo's
> 			% interface.
> then the interface of foo includes the interface of foo__bar.

No, `foo__bar's interface was already part of `foo's interface.
All the `import_module' declaration does is to make the symbols
declared in that sub-module visible in `foo'.  `import_module'
declarations are not transitive, so this declaration has no effect
on modules that import foo -- it only affects `foo' itself.

> So what
> is the effect of putting `:- include_module foo__bar' in the interface
> for foo, but not `:- import_module foo__bar'?

That would mean that modules which import `foo' can use things defined
in `foo__bar' (presuming they contain a use_/import_module declaration
for it, of course), but `foo' itself does not.

> > See the third item in the "Implementation bugs and limitations"
> > sub-section:
> > 
> >  |    * When using nested modules, the Mercury build tool Mmake sometimes
> >  |      tries to build things in the wrong order and hence reports
> >  |      spurious errors about `.int*' files not being found.  In these
> >  |      cases, simply typing `mmake' again will usually solve the problem.
> 
> Mea culpa.  What's the solution if a second mmake doesn't do the
> trick?

Use separate sub-modules rather than nested sub-modules.
(That is, put the sub-modules in a separate source file
included via `include_module', rather than textually
including them in the source of the parent module.)

> > Unfortunately there was a bug in 0.8 which meant that if the
> > end-module declaration for a sub-module is the last thing
> > in the containing module, the compiler would report a spurious error.
> > This bug was fixed in our development sources on Dec 17.
> > I've attached the patch.  The work-around, if you need to use 0.8,
> 
> 'fraid the patch never made it through.

I've attached it this time.

(But as you said, using the work-around of including an explicit
`end_module' declaration for the parent module is probably simpler.)

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh>  |   but source code lives forever"
PGP: finger fjh at 128.250.37.3        |     -- leaked Microsoft memo.
-------------- next part --------------
Index: make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.279
retrieving revision 1.280
diff -u -u -r1.279 -r1.280
--- make_hlds.m	1998/12/06 23:43:43	1.279
+++ make_hlds.m	1998/12/16 17:24:16	1.280
@@ -259,6 +259,14 @@
 			report_warning("Warning: `external' declaration requires arity.\n"),
 			io__set_output_stream(OldStream, _)
 		)
+	; { ModuleDefn = module(_ModuleName) } ->
+		report_unexpected_decl("module", Context),
+		{ Status = Status0 },
+		{ Module = Module0 }
+	; { ModuleDefn = end_module(_ModuleName) } ->
+		report_unexpected_decl("end_module", Context),
+		{ Status = Status0 },
+		{ Module = Module0 }
 	;
 		{ Status = Status0 },
 		{ Module = Module0 },
@@ -4759,6 +4767,16 @@
 %-----------------------------------------------------------------------------%
 
 	% Predicates to write out the different warning and error messages.
+
+:- pred report_unexpected_decl(string, prog_context, io__state, io__state).
+:- mode report_unexpected_decl(in, in, di, uo) is det.
+
+report_unexpected_decl(Descr, Context) -->
+	io__set_exit_status(1),
+	prog_out__write_context(Context),
+	io__write_string("Error: unexpected or incorrect `"),
+	io__write_string(Descr),
+	io__write_string("' declaration.\n").
 
 :- pred multiple_def_error(sym_name, int, string, prog_context, prog_context,
 				io__state, io__state).
Index: prog_io.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io.m,v
retrieving revision 1.178
retrieving revision 1.179
diff -u -u -r1.178 -r1.179
--- prog_io.m	1998/11/20 04:08:56	1.178
+++ prog_io.m	1998/12/16 17:24:18	1.179
@@ -288,11 +288,18 @@
 
 :- type module_end ---> no ; yes(module_name, prog_context).
 
-:- pred get_end_module(item_list, item_list, module_end).
-:- mode get_end_module(in, out, out) is det.
+:- pred get_end_module(item_list, module_name, item_list, module_end).
+:- mode get_end_module(in, in, out, out) is det.
 
-get_end_module(RevItems0, RevItems, EndModule) :-
+get_end_module(RevItems0, ModuleName, RevItems, EndModule) :-
 	(
+		%
+		% Note: if the module name in the end_module declaration
+		% does not match what we expect, given the source file name,
+		% then we assume that it is for a nested module, and so
+		% we leave it alone.  If it is not for a nested module,
+		% the error will be caught by make_hlds.m.
+		%
 		RevItems0 = [
 			module_defn(_VarSet, end_module(ModuleName)) - Context
 			    | RevItems1]
@@ -403,7 +410,7 @@
 	% check that it matches the initial module declaration (if any),
 	% and remove both of them from the final item list.
 	%
-	{ get_end_module(RevItems0, RevItems, EndModule) },
+	{ get_end_module(RevItems0, ModuleName, RevItems, EndModule) },
 	{ list__reverse(RevMessages, Messages0) },
 	{ list__reverse(RevItems, Items0) },
 	check_end_module(EndModule,


More information about the users mailing list