I remember I read somewhere it is not a macro and is built into the core language. Something like that, I am not sure, because I can no longer remember from where I read it. So is struct
a macro in Racket or not? If not, why is it built into the core language?

- 2,292
- 1
- 20
- 23
-
1Very few syntactic forms in Racket aren't macros: the complete list of non-macros is here: http://docs.racket-lang.org/reference/syntax-model.html#%28part._fully-expanded%29 – Paul Stansifer Jan 06 '14 at 05:21
4 Answers
A macro; struct.rkt
has
(define-syntax (struct stx)
(define (config-has-name? config)
(cond
[(syntax? config) (config-has-name? (syntax-e config))]
[(pair? config) (or (eq? (syntax-e (car config)) '#:constructor-name)
(eq? (syntax-e (car config)) '#:extra-constructor-name)
(config-has-name? (cdr config)))]
[else #f]))
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ id super-id fields . config)
(and (identifier? #'id)
(identifier? #'super-id))
(if (not (config-has-name? #'config))
(syntax/loc stx
(define-struct/derived orig (id super-id) fields #:constructor-name id . config))
(syntax/loc stx
(define-struct/derived orig (id super-id) fields . config)))]
[(_ id fields . config)
(identifier? #'id)
(if (not (config-has-name? #'config))
(syntax/loc stx
(define-struct/derived orig id fields #:constructor-name id . config))
(syntax/loc stx
(define-struct/derived orig id fields . config)))]
[(_ id . rest)
(identifier? #'id)
(syntax/loc stx
(define-struct/derived orig id . rest))]
[(_ thing . _)
(raise-syntax-error #f
"expected an identifier for the structure type name"
stx
#'thing)]))))
In Racket IDE, you can use the Open Defining File
function to locate the source code (if available).

- 18,732
- 2
- 34
- 52
-
Thanks for the answer. By the way, where is this _Open Defining File_ located in DrRacket? – day Jan 05 '14 at 12:10
-
In a definitions window, right-click on the word *struct* in your source code. The option should appear in the context menu. It sometimes doesn't work if Racket cannot parse the source correctly, so use it on a syntactically correct s-expr. – uselpa Jan 05 '14 at 13:05
-
Note that struct expands into `define-struct/derived`. New question: Is `define-struct/derived` a macro or a primitive? – soegaard Jan 05 '14 at 16:13
-
@soegaard Ultimately everything expands into the core forms. So the question is, what are Racket's core forms? – uselpa Jan 05 '14 at 16:15
-
1@soegaard: That is the _actual_ question I wanted to ask. I realized I had asked the wrong question only after I received @uselpa's answer which is perfect to it. So the right question should be whether the way to make _struct_ types is implemented as using macros or not. I have found the answer is no. I have traced all the way down from `struct`. You have reached `define-struct/derived`, which is also a macro defined in the file **define-struct.rkt**. – day Jan 05 '14 at 19:31
-
1@soegaard: Looking into its definition, you will find a procedure named `make-struct-type`, which is defined in [struct.c](https://github.com/plt/racket/blob/master/racket/src/racket/src/struct.c). That I guess means it is a primitive in the core language. – day Jan 05 '14 at 19:31
-
Because Lisps like Racket allow arbitrary changes to and extensions of syntax, the notion of core types doesn't carry much meaning - idiomatic operators such as `define` and `and` and `let` are often written as macros, since they only have an effect at compile time. Sure `struct` is a bit different but because it adds a new non-composite type to Racket's type system, it is more a matter of expediency than a philosophical decision - it is likely `struct` can be emulated with a kludge-up of macros contracts and objects. – ben rudgers Jan 05 '14 at 20:34
It looks like I misunderstood the question, when I answered before. So here's an answer to the question that was meant:
Structs are built-in and primitive; they underpin the implementation. In fact, circa 2007, Matthew Flatt commented that in PLT Scheme (as Racket was known then), in a sense everything is a struct:
> At Thu, 31 May 2007 16:45:25 -0700, YC wrote:
> Out of curiosity - does PLT scheme actually use struct as the fundamental
> compound type, i.e. implement closure/etc on top of struct.The way I think about it, everything is a struct, but some things use a special-case representation because they're important enough. (The extreme case is a fixnum).
But an equally valid answer would be: no, not all compound types use the same representation as values from a struct constructor.
-- Source.

- 16,100
- 6
- 36
- 53
-
Do you think Flatt holds this view because `struct foo` creates the type checking function, `foo?` and there are few obvious advantages to thinking about `integer?`, `boolean?`, etc. as being fundamentally different sorts of functions? – ben rudgers Jan 06 '14 at 17:13
-
Well, Matthew has spent decades thinking about the concepts and implementation, so I hesitate to put words in his mouth. It would be better if you ask _him_ on the mailing list. :) Having said that: Racket structs provide aggregation, encapsulation, inheritance, and application. Conceptually? All you need. Realistically? Maybe not. Because space and/or because speed. – Greg Hendershott Jan 06 '14 at 18:26
In addition to usepla's great answer, I wanted to add:
In the Racket documentation, the "blue box" has a phrase in the top right corner such as
procedure
orsyntax
. Forstruct
it sayssyntax
.If you think about what
struct
does, among other things it defines named functions derived from the name of the struct. So(struct foo (a b))
will define afoo?
predicate and accessorsfoo-a
,foo-b
. A plain function can't define new named things like this, so, it must be a macro.

- 16,100
- 6
- 36
- 53
-
I think the OP's question isn't about macro vs procedure, but macro vs builtin. – C. K. Young Jan 05 '14 at 23:47
-
Reading through the implementation code in define-struct.rkt, if you want to do the same thing manually, the following code is a much simplified version of what it is doing.
(define-syntax (struct stx)
;
; Function that creates compound names using syntax objects
(define (make-name id . parts)
(datum->syntax
id
(string->symbol
(apply string-append
(map (lambda (p)
(if (syntax? p)
(symbol->string (syntax-e p))
p))
parts)))
id))
;
(syntax-case stx ()
;
; parse the input and extract the name and variable
; this version uses only one variable for simplicity (3)
[(_ id avar)
;
; guard to ensure we have an identifier
(identifier? #'id)
;
; Create the names (1)
(let ((? (make-name #'id #'id "?"))
(v (make-name #'id #'id "-" #'avar)))
; Generate code to define the various functions associated with
; the new struct (2)
#`(begin
(define id (lambda (vx) (list id vx)))
(define #,? (lambda (x) (eq? (car x) id)))
(define #,v (lambda (x) (second x)))))]
))
1) We have to create the names we will define: but we need to use syntax objects to do so
2) We generate code that will define all of the functions associated with the new object in the global namespace
3) In the real version, most of the code deals with the properties that can be used a struct definition. The real version also needs to handle arbitrary numbers of variables and alternative forms, defaults etc...

- 121
- 5