bugMIT/GNU Scheme - Bugs: bug #64636, Libraries don't seem to close over...

 
 

bug #64636: Libraries don't seem to close over internal definitions upon which they depend.

Submitter:  Arthur A. Gleckler <aag>
Submitted:  Fri 08 Sep 2023 06:18:42 PM UTC
   
 
Category:  None Severity:  3 - Normal
Priority:  5 - Normal Item Group:  None
Status:  None Privacy:  Public
Assigned to:  None Originator Name: 
Open/Closed:  Open
Keywords: 
* Mandatory Fields

Add a New Comment Rich Markup
   

Mon 11 Sep 2023 04:53:27 AM UTC, comment #4: 

comment #3:

> I think this is the original problem that you want solved.  If not, speak up.


Yes, that's it.

> So the problem here has nothing to do with syntactic expansion; that works as designed.  The problem is, what do we do with the runtime reference to the syntactically-closed identifier I that has been inserted into L2?  There is no means in standard Scheme to resolve this identifier, so I can only conclude that the R7RS working group didn't think about this problem, or else they assumed that the implementation would provide an extra-linguistic mechanism to make it work.


It was the latter.  After all, Alex implemented it in Chibi Scheme.  It seems reasonable to let each implementer choose appropriate tradeoffs for the implementation in mind.

> I've started to develop a solution based on (3), though at the moment it's entirely manual.  See global-ref in "runtime/syntax-rules.scm" for a kludgy working example.  The reason I like this solution is that there's no performance hit at all; the compiler knows how to treat global references specially and they are just as fast as other top-level references.


That seems reasonable.

Arthur A. Gleckler <aag>
Group Member
Sun 10 Sep 2023 03:14:33 AM UTC, comment #3: 

comment #2:

> I have only a weak understanding of how hygienic macros are implemented, but I've always assumed that one would use something like syntactic closures to implement this.  In other words, a macro defined in one library would close over the environment in which it was defined, maintaining access to all the identifiers there.


This is correct and how MIT/GNU Scheme works.

> For references in procedures, rather than in macros, the usual environment mechanism would be used.  Perhaps that means no longer treating top-level definitions specially.


I'm not sure exactly what you mean here.  Let me work with an explicit example.

Suppose we have a macro M in library L1 that expands into code that refers to an identifier I.  M is exported from L1, but I is not.  Suppose also that we have a library L2 that imports M and there is a use of M that generates code referring to I.

I think this is the original problem that you want solved.  If not, speak up.

So the problem here has nothing to do with syntactic expansion; that works as designed.  The problem is, what do we do with the runtime reference to the syntactically-closed identifier I that has been inserted into L2?  There is no means in standard Scheme to resolve this identifier, so I can only conclude that the R7RS working group didn't think about this problem, or else they assumed that the implementation would provide an extra-linguistic mechanism to make it work.

I believe that, whatever mechanism is implemented, it is essentially equivalent to having a "universal environment" in which any identifier in any library can be looked up.

I can think of several mechanisms offhand:

1. Expand each non-local reference of I to (access I (library-environment L1)).
2. Create a "universal environment" and link I to a "universal name" in that environment, e.g. |<L1> <I>|, and expand each non-local reference of I to some code that accesses this.
3. Like (2) but use the global environment, arrange to hide the "universal name" from casual observation, and expand each non-local reference of I to (access |<L1> <I>| #f).

No doubt there are other ways to do this, but they will require more complex changes to the runtime system and compiler.  I think the main issue is that most of this changes will have significant performance consequences.

I've started to develop a solution based on (3), though at the moment it's entirely manual.  See global-ref in "runtime/syntax-rules.scm" for a kludgy working example.  The reason I like this solution is that there's no performance hit at all; the compiler knows how to treat global references specially and they are just as fast as other top-level references.

Chris Hanson <cph>
Group administrator
Sat 09 Sep 2023 11:02:32 PM UTC, comment #2: 

I have only a weak understanding of how hygienic macros are implemented, but I've always assumed that one would use something like syntactic closures to implement this.  In other words, a macro defined in one library would close over the environment in which it was defined, maintaining access to all the identifiers there.

For references in procedures, rather than in macros, the usual environment mechanism would be used.  Perhaps that means no longer treating top-level definitions specially.

Arthur A. Gleckler <aag>
Group Member
Fri 08 Sep 2023 11:14:54 PM UTC, comment #1: 

This is something I've been worried about for years now.

What I don't understand, and maybe the Chibi implementation will tell me, is how one can have a closed reference at runtime.  MIT/GNU Scheme has no simple means to make such a reference, other than transforming the output of the macro so that such references are in effect calls to ACCESS.

Do you have a better idea?

Chris Hanson <cph>
Group administrator
Fri 08 Sep 2023 06:18:42 PM UTC, original submission:  

In the following two library definitions, I would expect not to need to export quux from library bar in order to use it in exported macro baz.  After all, baz is defined in an environment in which it sees quux, so it should be closed over quux.  This works in Chibi Scheme.  In MIT Scheme, I get the error below.


(define-library (foo)
  (export bat)
  (import (bar))
  (import (scheme base))
  (begin
    (define (bat) (baz alpha bravo))))

(define-library (bar)
  (export baz)
  (import (scheme base))
  (begin
    (define (quux x y) (list y x))
    (define-syntax baz
      (syntax-rules ()
        ((_ a b) (quux 'a 'b))))))

1 ]=> (find-scheme-libraries! "$t/library-experiments/syntax-dependencies/")

;Registering library (bar) from "bar.sld"... done
;Registering library (foo) from "foo.sld"... done
;Unspecified return value

1 ]=> (ge '(foo))

;Loading "/home/arthur/tmp/library-experiments/syntax-dependencies/foo.sld"... done
;Loading "/home/arthur/tmp/library-experiments/syntax-dependencies/bar.sld"... done
;library: (foo)
;Value: #[environment 12]

1 ]=> (bat)

;Unbound variable: quux
;To continue, call RESTART with an option number:
; (RESTART 3) => Specify a value to use instead of quux.
; (RESTART 2) => Define quux to a given value.
; (RESTART 1) => Return to read-eval-print level 1.

2 error>


Arthur A. Gleckler <aag>
Group Member

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by cph (Posted a comment)
  • -email is unavailable- added by aag (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.

     

    No changes have been made to this item

    Back to the top

    Powered by Savane 3.13-caa5.
    Corresponding source code