[R6RS] modules

Richard Kelsey kelsey
Tue Aug 24 10:06:15 EDT 2004

   Date: Fri, 20 Aug 2004 00:39:35 -0500 (EST)
   From: "R. Kent Dybvig" <dyb at cs.indiana.edu>

   Here are some principles that I believe Matthew and I agree upon:

     * A standard form specifying the "language" in which a library is
       implemented should be wrapped around all libraries.


     * Require forms should be allowed in arbitrary local scopes to provide
       finer control over visibility.  Local require forms can also help
       prevent stale requires (requires that were once needed for a small
       portion of the module that has since been removed or rewritten).
       They can also obviate some renaming of imports.

I disagree with this.  The compiler can easily identify and indicate
stale requires much more accurately than a programmer.  The problem
with local require is that it subverts some of the utility of lexical
scoping.  Normally if two instances of FOO refer to different variables
then one or both will be lexically inside some form that explicitly
binds FOO (modulo unhygenic macros).  If FOO isn't lexically bound in a
file than all references to FOO in that file are to the same binding.
Local require changes this.  I wouldn't object to a local require that
had a body and explicitly named the identifiers being introduced.

     * We need something like require-for-syntax for specifying when the
       expressions and commands within a module are evaluated.  I propose
       that we actually have three flavors:

	 (require <spec> ...)
	 (require only-for-syntax <spec> ...)
	 (require also-for-syntax <spec> ...)

       possibly with some other syntax.

I agree.

     * Separate interfaces should not be required.  (But I don't think
       either of us minds if they are permitted.)

I agree.

     * The syntax given in Matthew's original post is a reasonable
       starting point.

   Here are some that we may not agree upon:

     * Should every r6rs program have the same kind of wrapper as is
       required for libraries?  (Matthew prefers so; I prefer not.)

I prefer not requiring the wrapper.

     * Should bindings established by run-time require shadow bindings
       that would otherwise be visible within transformers, and visa
       versa?  For example, if M exports x, does
	 (let ([x 3]) (require only-for-syntax M) x)
       evaluate to 3 or to an out-of-context error?  (I prefer error;
       I'm not sure about Matthew.)


     * Related to the above, should module expressions and commands be
       evaluated once for each "level" of require/require for-syntax or
       just once the first time needed?  (I prefer once; I'm not sure
       about Matthew.)

I'm unclear on both the question and the consequences of choosing one
or the other.  By 'module expresions and commands' do you mean the
code in the body of the module?  If so, doesn't evaluating each module
only once allow contagion between compile time and run time?

     * How are modules identified?  Possibilities include by name and
       by normalized pathname.  (I prefer by name with the pathname being
       advisory---information about where to find the module if it isn't
       already loaded.  I believe that Matthew prefers by normalized
       pathname, which is what MzScheme currently does.)

I would like to drop the pathname entirely.  Failing that, it should
be advisory.

   Here are some that we did not talk about much if at all;

     * Are module exports settable by the exporting module and/or importing
       module? (I prefer that modules be used to control scope, not mutation
       policy, so I would say that variables are settable.  one can always
       export accessors/setters for hidden exports to obtain finer control.)

Not settable.  I would like to go further and prohibit any assignment
of exported variables, including in the exporting module.  SET! on a
an exported variable is rare enough that it's nice to know that it
can't happen at all.

     * Can more than one module appear in a file?  (If modules are identified
       by normalized pathname, it probably makes sense to have only one
       module per file; otherwise more than one may be reasonable.)


     * Must one declare "implicit" exports, i.e., local identifiers,
       references to which may be contained in the expanded output of an
       exported macro?  (I prefer yes, since this improves security and
       gives the implementation a chance to treat the remaining variables
       more efficiently.)

No.  Implicit exports are the business of the implementation, not the
programmer.  This seems akin to requiring that the programmer list the
closed-over variables in a lambda.

More information about the R6RS mailing list