[racket] Macros that expand to field and method definitions
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