Hello all, Andreas has been struggling with a nonstandard behavior of Guile's recently, and we should discuss it more directly.
The issue is in expressions like this: (define-syntax define-accessor (syntax-rules () ((_ getter setter init) (begin (define val init) (define getter (lambda () val)) (define setter (lambda (x) (set! val x))) (define-accessor get-x set-x! 0) The issue is, what happens when this expression is expanded? Within a let or a lambda, it expands to an three internal definitions: `val', `getter', and `setter', where `val' is only visible to within the `getter' and `setter' procedures. At the top level, it expands to three definitions: "val", the getter, and the setter. However in this case the "val" binding is global to the module, and can be referenced by anyone. This is what happens in Guile. I know that some other Schemes do different things. Chez, as far as I understand it, binds "val" in the module, but under a gensym'd name. It can do this because its modules are syntactic: the bindings in a module are not serialized to disk as simple symbol-binding pairs, but rather the whole expansion-time ribcage is also written out. That's how I understand it anyway; I could be getting things wrong there. Anyway, in Guile our modules have always been first-class entities. We never intern gensym'd names in modules, because who would do that? You put a name in a module because you want to be able to name it, either internally or externally, and gensym'd names don't make any sense without some sort of translation table, and Guile's first-class modules have no such table. Furthermore, gensyms at the top-level have a cost that they do not have lexically. When you introduce a lexical binding in a macro and cause a new name to be allocated to it, that binding only exists within the scope of that form -- if the form is an expression, it exists during the dynamic extent of that expression, and if it is a definition, its extent is bound to the extent of the binding of some /other/ name---the top-level name. But when you introduce a generated name to the top-level, you create some trash "val-12345543" binding which will always be there, and you don't know why. It can never be removed by normal means, because top-level bindings are never removed, and its name is invisible to all other code -- it has infinite extent. And that's the thing that really bothers me about generated top-level names: they are only acceptable if you plan on never changing your mind. You're not bothered by the trash name, because you'll never expand that expression again. So! That's my rant. But this is, even more than usual, a case in which I could simply be wrong; so if you really want to defend generated top-level names, now would be a great time to do so ;-) Cheers, Andy -- http://wingolog.org/