[plt-scheme] Re: cannot require 19.ss (srfi)

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Thu Jan 6 12:29:44 EST 2005

Hans Oesterholt-Dijkema wrote:

>> Since SRFI 19 defines names that conflict with primitives in the
>> mzscheme language, two modules are provided: srfi/19.ss provides the
>> names as defined in the SRFI document, srfi/19/time.ss provides `srfi:'
>> prefixed identifiers where clashes with mzscheme occur (eg.
>> srfi:make-date, srfi:date?, etc). 19.ss is meant to be used from the
>> top-level to write portable programs, whereas time.ss is convenient
>> to use when writing PLT modules.
>
>
> Since I've included 19.ss, and thus want these primitives, why doesn't 
> 19.ss
> just override the existing primitives?

Suppose the module system did override conflicting names quietly. 
Consider now the situation, where you
require the library A in order to use the function foo, and require the 
library B in order to use bar. To your
great surprise something unexpected happens when using foo. What 
happened? The library B incidently
also exported a function named foo (which you wasn't aware of, since it 
was written by a friend), and
thus overrided the foo from A. Such a bug could be very time consuming 
to find.

In order to squash this kind of bug, the module system demands that all 
names inside a module
are defined only once. (Hm. I thought it was somewhere in chapter 12 of 
the PLT MzScheme Langauge
Manual).

The most often occurence of conflicting names is when one requires 
srfi-1 with (require (lib "srfi" "1.ss")).
The problem is that srfi-1 exports improved version of some of the 
normal r5rs primitives, thus a
conflict arises with all the normal PLT languages.

E.g.:

  (module foo mzscheme
    (require (lib "1.ss" "srfi")))

will give the error

    "module: identifier already imported (from a different source) in: 
reverse!"


There are several solutions:

  1. Import all of the srfi-1 except reverse! (and the other redefined 
names),
      then import the remaining names one at time, while renaming them.

  (module foo mzscheme
    (require
     ; import all from srfi-1 except the already defined names
     (all-except (lib "1.ss" "srfi")
                 reverse! member map for-each assoc append!)
     ; import one name at a time from srfi-1, renaming at the same time
     (rename (lib "1.ss" "srfi") srfi:reverse!  reverse!)
     (rename (lib "1.ss" "srfi")srfi:member    member)
     (rename (lib "1.ss" "srfi")           srfi:for-each  for-each)
     (rename (lib "1.ss" "srfi")           srfi:assoc     assoc)
     (rename (lib "1.ss" "srfi")           srfi:append!   append!))
 
    ; Now both functions can be used in the module body
 
    (display (reverse!      (list 1 2 3)))
    (display (srfi:reverse! (list 1 2 3))))

  Now   (require foo)  will display   (3 2 1)  (3 2 1)

  NB: If you don't intend to use the conflicting names, then all you need is
          to ban them with the (all-excpet ...). No need to rename them.


  2. Use another language than mzscheme for your module.

  ; mini-mzscheme.scm
   (module mini-mzscheme mzscheme
    (provide
     (all-from-except mzscheme
                      reverse! member map for-each assoc append!)))

  ; foo.scm
  (module foo "mini-mzscheme.scm"
      (require
       ; import all from srfi-1
       (lib "1.ss" "srfi"))
 
      ; Now only the srfi-1 versions are availble
      (display (reverse! (list 1 2 3))))


In the case of srfi-1 the PLT packaging provides "list.ss", which
exports the troublesome names with a s: -prefix:

    (require (lib "list.ss" "srfi" "1"))


The above discussion also applies to srfi-19.


NOTE:  Please move this line further up in the doc-page for srfi.
             On a normal size screen the special info about srfi-1 doesn't
             appear on the first page.

-- 
Jens Axel Søgaard




Posted on the users mailing list.