[racket] Macros that expand to field and method definitions

From: Patrick Mahoney (paddy.mahoney at gmail.com)
Date: Wed Apr 25 13:30:40 EDT 2012

#|An update: here is what the macro looks like now.|#
(define-syntax (define-property stx)
   (define make-id
     (lambda (template . ids)
       (define str (apply format template (map syntax->datum ids)))
       (datum->syntax stx (string->symbol str))))
  (syntax-parse stx
                [((~literal define-property) name:id init-value)
                 (with-syntax ([getter-name (make-id "get-~a" #'name)]
                               [setter-name (make-id "set-~a" #'name)])
                   #'(begin (define name init-value)
                            (define/public (setter-name value)
                              (set! name value))
                            (define/public (getter-name)
                              name)))]
                [((~literal define-property) name:id init-value ((~literal
get:expr) get-body))
                 (with-syntax ([getter-name (make-id "get-~a" #'name)])
                   #'(begin (define name init-value)
                            (define/public (getter-name)
                              get-body)))]
                [((~literal define-property) name:id init-value ((~literal
set)  (setter-vars:id ...) set-body:expr))
                 (with-syntax ([setter-name (make-id "set-~a" #'name)])
                   #'(begin (define name init-value)
                            (define/public (setter-name setter-vars ...)
                              set-body)))]
                [((~literal define-property) name:id init-value ((~literal
get) get-body) ((~literal set) (setter-bindings:id ...) set-body:expr))

                 (with-syntax ([getter-name (make-id "get-~a" #'name)]
                               [setter-name (make-id "set-~a" #'name)])
                   #'(begin (define name init-value)
                            (define/public (setter-name setter-bindings ...)
                              set-body)
                            (define/public (getter-name)
                              get-body)))]))

Somewhat like
http://msdn.microsoft.com/en-US/library/w86s7x04%28v=vs.80%29.aspx, but
with mandatory initialization expressions for each property.

-Patrick

On 25 April 2012 10:10, Asumu Takikawa <asumu at ccs.neu.edu> wrote:

> 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20120425/b9f92406/attachment-0001.html>

Posted on the users mailing list.