How do you find out the fields and properties of a struct?

Viewed 867

The question

Suppose you have a struct, like this:

(struct soldier (name rank serial-number) #:transparent)
(define s (soldier 'Smith 'private 100134))

How can you find out what fields soldier or s contains? Or what generic interfaces it supports, or what structure type properties it has?


Research efforts so far

(Skip this section if you already know the answer.)

I've been reading through the documentation on structs for the last few days, and I haven't been able to figure out how you're supposed to put the pieces together. I'm probably just missing some elementary tidbit of information that goes without saying to people who know Racket.

The chapter on Reflection and Security has a section "Structure Inspectors", which says:

An inspector provides access to structure fields and structure type information without the normal field accessors and mutators.

but I haven't understood how to get an inspector to provide that.

struct-info and struct-type-info provide some information, but not field names, interfaces, properties, etc.:

> (struct-type-info struct:soldier)
'soldier
3
0
#<procedure:soldier-ref>
#<procedure:soldier-set!>
'(0 1 2)
#f
#f

struct->vector and struct->list provide access to an instance's contents and the above data, but that's all:

> (struct->vector s)
'#(struct:soldier Smith private 100134)

If you could show me an example of how to inspect a struct type to see what's in it, that would probably clarify whatever soon-to-be-obvious-in-hindsight thing I'm not seeing here.

1 Answers

The field names are not available at run time. However you can at expansion time use syntax-local-value on the struct name to get some information.

A quick example:

#lang racket
(require (for-syntax racket/struct-info))

(struct foo (a b))
(begin-for-syntax
  (display (extract-struct-info (syntax-local-value #'foo))))

Update

In this example:

#lang racket
(require (for-syntax racket/struct-info))

(struct foo (a [b #:mutable] c))
(begin-for-syntax
  (display (extract-struct-info (syntax-local-value #'foo))))

The list of identifiers for mutators is: (#f #<syntax:4:8 set-foo-b!> #f). That is only the second field is mutable.

The information is available at expansion time, so you can transfer the information to runtime by calling a macro that expands into a definition like (define info '(#f set-foo-b! #f) or similar.

Related