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.
* Separate interfaces should not be required. (But I don't think
either of us minds if they are permitted.)
* The syntax given in Matthew's original post is a reasonable
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
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
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
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