On 26-Mar-09, at 11:25 PM, James Long wrote:
I second Brad's comment. Support for hygienic macros should be on the feature list (you can still provide unhygienic macros as well). This is important because it requires changes to the evaluator (I think), and is something that can't be added on.
Your module system looks cool, Marc. I built something on top of Gambit's namespaces a while ago as well. It uses Scheme48's module language however (which I am partial to). Whenever we get Gambit's low-level module system built the first thing I hope to do is write a scheme48-like module language on top of it!
I hit one major problem with namespaces, however, which your module system is also prone to since it's built on top of the namespaces. I posted a message to this list a while ago about it:
https://webmail.iro.umontreal.ca/pipermail/gambit-modules-list/2009-January/...
Basically, something's a little funky with how DEFINE expressions are evaluated. When the evaluator evaluates the identifier provided to DEFINE, it can evaluate to an identifier in a different namespace. See my post above for examples with the namespace mechanism. I haven't had time to look through Gambit's source to understand why this happens. Here are a few examples in your system:
EXAMPLE 1 (wrongly overrides another library):
(##module library1 gambit (export foo bar))
(define (foo) (display "[library1] foo'ing\n"))
(define (bar) (display "[library1] bar'ing\n") (foo))
(##module library2 gambit) (##use library1)
(define (foo) (display "[library2] foo'ing (this should never be called)\n"))
(display "[library2] calling out to BAR in library1\n") (bar)
I don't view this as a bug. One interpretation of (define v ...) is (set! v ...) in an environment where v existed, and that's how Gambit has viewed "define" since the beginning. It has the nice feature that it fits well with the REPL (i.e. you can re-define a faulty procedure declaration). You are asking for "define" to do more than this. You want "define" to create a new variable even if it existed previously. Perhaps your example looks like a real bug to you, but a slight variant of it looks like a real problem to me:
(##module m1 gambit (export foo)) (define (foo) (print "m1#foo\n"))
(##module m2 gambit) (##use m1) (define (bar) (foo)) ;; refers to which foo? ;... lots of definitions ... (define (foo) (print "m2#foo\n"))
Perhaps issuing a warning is the right thing to do when defining a variable that is imported.
% gsi -e '(include "modules.scm")' foo.scm [library2] calling out to BAR in library1 [library1] bar'ing [library2] foo'ing (this should never be called)
EXAMPLE 2 (dangerously overrides a global function):
(##module library1 gambit (export foo bar))
(define (integer->char i) (display "bar#integer->char\n"))
(##module library2 gambit) (##use library1)
(integer->char 5)
% gsi -e '(include "modules.scm")' library2.scm bar#integer->char
Here too I don't see this as a bug due to my interpretation of "define" = "set!". Note that when in library1 you
(define (integer->char i) (display "bar#integer->char\n"))
you are really defining the global variable "integer->char" and *NOT* "library1#integer->char" (so obviously the message printed is misleading, beyond the typo... I assume you meant to print "library1#integer->char").
If you had exported integer->char from library1, i.e.
(##module library1 gambit (export foo bar integer->char))
(define (integer->char i) (display "bar#integer->char\n"))
then indeed you would have defined the global variable "library1#integer->char" (and the message printed, the same, would have been appropriate).
So my conclusion is that you don't like "define" = "set!" + allocation of global var if it doesn't exist. Right?
Marc