Winny
Winny

Reputation: 1278

Get a struct's field names

In Racket, I want to use a struct's field names for metaprogramming.

For example:

(struct pt [x y])
(struct-fields pt) ;; -> '(x y)

Upvotes: 0

Views: 514

Answers (1)

Alexis King
Alexis King

Reputation: 43852

You can’t. You can get the accessors, which here would be pt-x and pt-y, but you can’t get just x and y alone. Why is this? Well, one reason is that there could actually be duplicates. Consider a scenario involving some pernicious struct subtyping:

#lang racket/base

(struct A [x] #:transparent)
(struct B A [x] #:transparent)

Now a structure of type B has two x fields, A-x and B-x. For this reason, any macro that tries to use field names alone with structs is broken when subtyping may be involved.

What you can do is use the accessors, instead, which you can achieve by using syntax-local-value plus extract-struct-info, then looking at the fourth element of the resulting list. However, honestly, I think that’s too much work, so I wrote a syntax class to do all the hard work for you. Install the syntax-classes package and use the struct-id syntax class:

#lang racket/base

(require (for-syntax racket/base
                     syntax/parse/class/struct-id)
         syntax/parse/define)

(define-simple-macro (struct-accessors id:struct-id)
  (list id.accessor-id ...))

> (struct pt [x y] #:transparent)
> (struct-accessors pt)
'(#<procedure:pt-x> #<procedure:pt-y>)

Upvotes: 2

Related Questions