[racket-dev] Keyword Constructors for Structs

From: Walter Tetzner (walter at waltertetzner.net)
Date: Sat Aug 18 21:54:08 EDT 2012

I've updated define-struct/derived to allow creating a keyword
argument constructor.

https://github.com/wtetzner/racket/compare/v5.3...struct-keyword-args?w=1

It would be good to get some feedback on:
  - whether or not the option's design is good
  - if I did anything stupid in the implementation
  - if there are any cases I didn't cover that will cause things to break

All of the collects build fine with the changes, so I haven't (yet)
found any cases where it breaks existing code.

There is one thing I don't know how to do, but would like to
have. When the keyword constructor is the only constructor, it would
be nice if the default print for transparent structs would print with
keywords.

It works like this:

If you give a name that's the same as the positional constructor, only
the keyword constructor will be defined:

(struct person (name age height weight)
  #:transparent
  #:keyword-constructor person)

> (person #:name "Bob" #:height 6 #:age 45 #:weight 200)
(person "Bob" 45 6 200)

By default, all keyword arguments are required. You can set a default
value for all fields, or specific defaults for individual fields:

(struct person (name age height weight)
  #:transparent
  #:keyword-constructor [person #:default #f])

> (person #:name "Bob" #:height 6)
(person "Bob" #f 6 #f)

(struct person (name age height weight)
  #:transparent
  #:keyword-constructor [person #:default #f
                                (weight 200)])

> (person #:name "Bob" #:height 6)
(person "Bob" #f 6 200)

(struct person (name age height weight)
  #:transparent
  #:keyword-constructor [person (weight 200)])

> (person #:name "Bob" #:height 6 #:age 45)
(person "Bob" 45 6 200)

If the constructor name is different from the positional constructor
name, you get both constructors:

(struct person (name age height weight)
  #:transparent
  #:keyword-constructor make-person)

> (person "Bob" 45 6 200)
(person "Bob" 45 6 200)

> (make-person #:name "Bob" #:age 45 #:height 6 #:weight 200)
(person "Bob" 45 6 200)

(struct person (name age height weight)
  #:transparent
  #:constructor-name make-person
  #:keyword-constructor person)

> (make-person "Bob" 45 6 200)
(person "Bob" 45 6 200)

> (person #:name "Bob" #:age 45 #:height 6 #:weight 200)
(person "Bob" 45 6 200)

-Walter

Posted on the dev mailing list.