Fergus Henderson writes:
I don't think three levels is really satisfactory. Let me give an
example. The Mercury implementation (0) includes source code for
several programs, the largest of which is the Mercury compiler (1).
The Mercury compiler is in turn composed of a number of libraries
plus the object files for the compiler itself (2). The compiler
is composed of a number of major sub-components (3).
For example, one of these sub-components is
called the "High Level Data Structure" or HLDS. The implementation of
this subcomponent is divided into modules (4), called hlds_goal,
hlds_pred, hlds_module, hlds_data, and hlds_out, each relating to a
particular aspect of the HLDS, with a separate source file for each
module. Each of these modules defines several different abstract data
types and/or groups of related operations, which should really
themselves each be sub-modules (5), since (in both Mercury and Haskell)
the module is the unit of encapsulation.
(0) distribution:
Mercury, ghc, hugs, ...
(1) programs (within the Mercury distribution)
mmc, mprof, diff, ...
(2) top-level components/libraries (of mmc)
compiler, standard library, runtime, GC, debugger, ...
(3) major sub-components (of compiler):
parse tree, HLDS, LLDS, type checker, mode checker,
determinism analysis, code generator, optimizer,
value numbering, ...
(4) modules (for HLDS):
hlds_data, hlds_goal, hlds_pred, hlds_module, hlds_out
(first four are high-level representations of data, goals,
predicates, and modules in the language being compiled;
the last is routines to pretty-print these)
(5) sub-modules (of hlds_data)
constructors, types, insts, modes, type classes
(these are ADTs or functional groups within a module)
<snipping the discussion...>
OK, I am confused (I *still* suspect I am missing something basic).
As far as I can see, the depth of the call tree (what VHDL calls the
design hierarchy) has nothing to do with the need for an
arbitrary-depth library directory structure. To be specific:
5) The submodules of HLDS all export the names they need internally,
and a gather module in that directory imports and exports names
that are visible to HLDS.
4) The modules of HLDS import the gather module of the submodules,
along with other modules at their same level; a gather module
imports the names for export from the entire "package" and exports
them.
(3) The major subcomponents import the HLDS module and other imports
at their own level; a gather module exports names farther up the
design tree.
And so on.
If the argument is that there are times when a module at level (3)
will need a name at level (5), and therefore the nested module name
makes sense in this case: to my mind, this is a sufficient violation
of information hiding that it deserves explicit documentation, in the
form of another gather module at level (5) containing the
"skip-a-level" names, which the module at level (3) imports separately
from the module at level (4). I regard the provision of some sort of
infinitely nested module / name pair as encouraging this kind of
violation of information hiding (note there is nothing wrong with a
gather module at level (4) reexporting a name from level (5) if it is,
indeed, part of the interface).
All this makes particular sense in a functional language, which has no
state bearing objects to be addressed. In the presence of state,
there may be times when multi-level name threading is necessary to get
at a specific state bearing object (VHDL handles this outside the
normal with-use mechanism). In the absence of such considerations, I
really see no argument whatever for an arbitrary number of levels of
module name spacing.
Dave Barton <*>
[EMAIL PROTECTED] )0(
http://www.intermetrics.com/~dlb