[racket] Macros that expand to field and method definitions

From: Asumu Takikawa (asumu at ccs.neu.edu)
Date: Wed Apr 25 10:10:57 EDT 2012

On 2012-04-25 03:19:46 -0400, Patrick Mahoney wrote:
>    I'm looking to define a macro that extends the forms within a racket/class
>    class%. In particular, I would like a form to define a C# like class
>    language form property, that implements the getters and setters for an
>    initialized field automatically.

FYI, `get-field` and `set!-field` already allow you to get and set any
public fields on an object.

>    (define-syntax (define-property syntax)
>      (syntax-parse syntax
>                    [((~literal define-property) name:id init-value)
>                    
>                     #'(define name init-value)
>                     (define/public (set-name! init-value)
>                       (set! name init-value))
>                     (define/public (get-name)
>                           name)]))

So this macro won't quite work as written. Here's an alternative that
will at least run (but still won't work as you expect):

(define-syntax (define-property stx)
  (syntax-parse stx
    [(_ name:id init-value)
     #'(begin (define name init-value)
              (define/public (set-name! new-val)
                (set! name new-val))
              (define/public (get-name) name))]))

One issue was that you were using `syntax` as the argument to this
transformer, which won't work because you end up shadowing
`syntax`, which is needed to write the template. I changed it to `stx`.

Secondly, you need to use `begin` to splice all of the definitions
together.

Note that this still doesn't work though. The `set-name!` and `get-name`
will be introduced as is (or hygienically renamed) and won't use the
name of the field as you might want. To do that, you might want to write
`define-property` so that it takes get/set method names as arguments.[1]

[1]: otherwise you need to unhygienically introduce a binding, which
     is best to avoid unless you know what you are doing.

>    define/public: use of a class keyword is not in a class top-level in:
>    (define/public (set-name! init-value) (set! name init-value))

You probably got this error by trying out the macro outside of a class
or because you weren't splicing the definition quite right.

Cheers,
Asumu

Posted on the users mailing list.