[racket] struct constructors
On Tue, May 27, 2014 at 07:25:34PM +1200, Aidan Gauland wrote:
> What's the nearest equivalent for a struct to constructors for class
> instances? Say I have a struct with a field that should be initialised
> to a three-element vector. Right now, I'm just defining a wrapper
> make-blah.
>
> (struct blah (a b c v))
>
> (define (make-blah)
> (blah 0 0 0 #(0 0 0))
I often create a wrapper like this. The wrapper can initialize fields
as in your example but it can also be used to produce side effects like
registering the instance in a container, for instance. The main
drawback with this wrapper solution is with subtyping: either you
prevent subtyping by not `provide'ing the struct id transformer binding,
or you allow subtypes but live with the fact that instances of the
subtypes will not be created through your wrapper.
Another solution is to make the field(s) #:auto so they get a default
value automatically. The main drawback here is that there is only one
default value per struct type (defaults to #f but can be changed with
#:auto-value.) For example:
(struct blah2 (a b c [v #:auto]) #:auto-value #(0 0 0))
A third possibility is to specify a #:guard procedure that verifies the
values passed to the constructor conform to whatever constraints you
wish to impose. For example:
(struct blah3 (a b c v)
#:guard (lambda (a b c v name)
(unless (and (vector? v) (= (vector-length v) 3))
(raise-arguments-error name "v must be a 3-element vector"
"v" v))
(values a b c v)))
Note that you could use the #:guard procedure to produce field values at
instantiation time without using a wrapper function, but the drawback is
that it can only do so for fields which are *not* #:auto. Therefore the
calling code must still provide values when calling the constructor,
even if they get ignored by the #:guard procedure.
David