[plt-scheme] Shadowing imported bindings

From: Bradd W. Szonye (bradd+plt at szonye.com)
Date: Fri Oct 24 13:53:09 EDT 2003

> "Bradd W. Szonye" wrote:
>> It seems to me that shadowing would be simpler from the user's point
>> of view, but it might cause problems with "what does this code really
>> mean?" since module bindings cover the entire module scope.

Matthew Flatt wrote:
> That's it exactly. Multiple definitions/imports of a identifier are
> disallowed for the same reason that multiple bindings of an identifier
> are disallowed in "letrec".

And on second thought, I agree that it was the right choice.

For context, here's an example that has been bothering me. As you
already know, I'm adapting Michael Sperber's SRFI-7 to work as a "module
language" (i.e., as an initial-import module). Usage example:

    (module my-program (lib "7.ss" "srfi")
      (program (code ...)))

instead of the current

    (module my-program mzscheme
      (require (lib "7.ss" "srfi"))
      (program (code ...)))

I'm doing this for two reasons: First, it reduces the amount of
scaffolding necessary to use PROGRAM. Second, it lets me enforce
SRFI-7's grammar, which states that there can only be one PROGRAM in the
configuration language. In other words, it recognizes the fact that
SRFI-7 describes a different *language*. While the configuration
language is Scheme-like, it is not Scheme. The best way to represent
that in PLT Scheme is with the initial import. The infotab language is
another good example of this.

So far, everything's OK. However, I also wanted to provide a
LOAD-PROGRAM procedure (analagous to LOAD for SRFI-7 programs, as
described in the SRFI). The obvious place to put this was in the SRFI-7
module. That way, you'd have two options for using the configuration
language: Use a module language, or use a procedure. Unfortunately, when
a user writes:

    (module my-loader mzscheme
      (require (lib "7.ss" "srfi"))
      (load-program "foo.scf"))

... there's an error, because the module now has two different
definitions of #%module-begin: one from mzscheme and one from SRFI-7. In
other words, a "language module" does not work well as a "library

However, that's probably a good thing (which I realized just before I
saw your response). In this case, shadowing would do the *wrong* thing:
it would change the language for my-loader from PLT Scheme to the SRFI-7
configuration language! In this case, you don't *want* to shadow the
standard #%module-begin.

There is a work-around for this:

    (module my-loader mzscheme
      (require (all-except (lib "7.ss" "srfi") #%module-begin ...) ...))

In other words, when loading it as a "library" instead of a "language,"
omit all of the stuff like #%module-begin and #%top that makes it a
language. You can even select some but not all of the language features.
And you can merge multiple languages+libraries by writing an "adapter"
module that carefully chooses what it provides from the originals.

So this stuff makes life a bit more complicated for users, but they do
get total control over what they get. Still, I wish there were some
require form that makes it easier to use "double-duty" modules like
this. Perhaps something similar to require-for-syntax:

    (require spec)

implicitly omits "language" features like #%module-begin, #%top, etc.

    (require-for-language spec)

works the way require does now, for the rare cases that you really do
want to import language features inside the module body. I'm not sure
whether this is a good idea. It would make my example a lot easier for
users, but it may have undesirable side-effects that I haven't thought
of yet.
Bradd W. Szonye

Posted on the users mailing list.