[plt-scheme] Dot-notation for structure field access

From: jos koot (jos.koot at telefonica.net)
Date: Mon Mar 19 09:22:33 EDT 2007

Hi Matthew
Thanks, that 's quick and clear. It took you less time for you to answer me than for me to read your answer. Thanks, Jos Koot. 

(Warning to others: module dot should be discouraged because it has some nasty shortcomings I am still working on. To solve these shortcomings requires runtime registers too. They cannot be solved in the expansion phase)

(((((lambda(x)((((((((x x)x)x)x)x)x)x)x))
    (lambda(x)(lambda(y)(x(x y)))))
   (lambda(x)(x)x))
  (lambda()(printf "Greetings, Jos~n"))))
  ----- Original Message ----- 
  From: Matthew Flatt 
  To: jos koot 
  Cc: plt-scheme at list.cs.brown.edu 
  Sent: Monday, March 19, 2007 7:56 AM
  Subject: Re: [plt-scheme] Dot-notation for structure field access


  At Sun, 11 Mar 2007 12:49:17 +0100, "jos koot" wrote:
  > Inspired by the dot notation of Jens Axel Søgaard I tried to eliminate the 
  > need for define-accessor. See enclosure. However, I can't get rid of the error 
  > reported at the end of my trial, reading:
  > "compile: bad syntax; reference to top-level identifier is not allowed, 
  > because no #%top syntax transformer is bound in: acc85"

  The problem starts here:

   (define-syntax (define-struct-type stx)
    (syntax-case stx ()
     ....
     ((define-struct-type (descr constr pred super) (field ...) inspector)
      (let-values (((acc mut) (apply values (generate-temporaries #'(acc mut)))))
       (register-transformer-builder #'constr #'(field ...) acc mut)
     #`(define-values (descr constr pred #,acc #,mut)
         ....)))))

  The call to `register-transformer-builder' is a side effect that
  happens while the macro is expanded. After a `define-struct-type' form
  is expanded --- say, when compiling a module --- the side-effect won't
  happen anymore. In particular, the side effect won't happen if you
  (next week, on a different machine) load the compiled form of module
  whose source contains the `define-struct-type' declaration.

  Well, the error you see is only indirectly related to the problem,
  which is partly why it's difficult to track down. The problem is that
  the registration uses `acc' and `mut' identifiers before any such
  bindings exist, and that leads to the bad reference.

  The solution to both problems is the same, and it's simple to write
  down:

   (define-syntax (define-struct-type stx)
    (syntax-case stx ()
     ....
     ((define-struct-type (descr constr pred super) (field ...) inspector)
      (let-values (((acc mut) (apply values (generate-temporaries #'(acc mut)))))
       #`(begin
           (begin-for-syntax
            (register-transformer-builder #'constr #'(field ...) #'#,acc #'#,mut))
           (define-values (descr constr pred #,acc #,mut)
             ....))))))

  All I've done is move the `register-transformer-builder' call into the
  result of the macro, so that it's a side-effect wrapped by
  `begin-for-syntax'. Since it's part of the result expansion, the side
  effect happens each time the expanded (or compiled) expression is
  loaded.

  Moreover, `acc' and `mut are now in the same binding context as the
  `define-values' form, so they get bound in the way that you want.


  The general rule is: Don't put any side-effects in a macro expansion.
  If you must have side effects at compile time, they should be in
  `begin-for-syntax'.


  See also 
    http://www.cs.utah.edu/plt/publications/macromod.pdf
  which may make more sense now that you've hit the problem that it
  describes. :)


  Unfortunately, there's a small catch, which I think is almost certainly
  related to your later question about `syntax-recertify'. If you try

   (module m mzscheme
     (require dot)
     (define-struct-type d c p (x y z) (make-inspector))
     (provide d c p))

   (module n mzscheme
     (require dot m)
     (define-struct-var s (c 1 2 add1))
     (printf "~s\n" s.x))

  then you get

   compile: access from an uncertified context to unexported variable
   from module: m at: acc1 in: acc1.1

  Even though there's no `local-expand' in the macro implementation,
  there is a kind of manual expansion that happens when looking up a
  binding via `register-lookup'. That manual lookup must be accompanied
  by manual management of certificates (though not through using
  `syntax-recertify').

  So, explicitly certify the referencing identifiers before you record
  them:

   (define-syntax (define-struct-type stx)
    (syntax-case stx ()
     ....
     ((define-struct-type (descr constr pred super) (field ...) inspector)
      (let-values (((acc mut) (apply values (generate-temporaries #'(acc mut)))))
       #`(begin
           (begin-for-syntax
            (let ([cert (syntax-local-certifier)])
              (register-transformer-builder #'constr #'(field ...) 
                                            (cert #'#,acc)
                                            (cert #'#,mut))))
           (define-values (descr constr pred #,acc #,mut)
             ....))))))

  Revised code and example enclosed.

  Matthew
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20070319/316d10fa/attachment.html>

Posted on the users mailing list.