[racket] dynamically auto-initialized private struct fields

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Sun Nov 10 12:36:13 EST 2013

Have you considered classes instead of structs? -- Matthias



On Nov 9, 2013, at 12:50 PM, David T. Pierson wrote:

> Hi all,
> 
> Sometimes when defining struct types it is useful to have fields which
> are essentially "private" to the module (fields whose accessors/mutators
> are not exported from the module.) I want these fields to be initialized
> automatically with arbitrary values generated at construction time.
> 
> Here are some methods I've considered and what I don't like about them:
> 
> 1) Create a wrapper around the generated constructor which provides the
> correct values for the private fields:
> 
> (provide make-mystruct1
>         mystruct1-public)
> (struct mystruct1 (public private))
> (define (make-mystruct1 public)
>  (mystruct1 public (get-new-private)))
> 
> The downside of this method is that you can't allow arbitrary subtypes
> outside the module because they'd have to supply an invalid value for
> the private field.
> 
> 2) To fix the subtype constructor problem, we could make the fields
> #:auto and provide a separate init procedure:
> 
> (provide mystruct2
>         make-mystruct2
>         init-mystruct2
>         mystruct2-public)
> (struct mystruct2 (public [private #:auto])
>        #:constructor-name make-mystruct2
>        #:mutable)
> (define (init-mystruct2 m2)
>  (set-mystruct2-private! m2 (get-new-private)))
> 
> Now subtype constructors need not specify a bogus value for the private
> field, but the init procedure is not elegant.  (Wrappers could be
> defined for each type/subtype constructor which also call the init
> procedure.)
> 
> 3) Specify a guard procedure:
> 
> (provide mystruct3
>         make-mystruct3
>         mystruct3-public)
> (struct mystruct3 (public private)
>        #:constructor-name make-mystruct3
>        #:guard (lambda (public private-ignored name)
>                  (values public (get-new-private))))
> 
> Here the guard procedure provides a valid value for the private field,
> but unfortunately the constructor and subtype constructors still need to
> take a bogus value for the private field (which will be ignored in the
> guard.)  Like the init procedure method, that could be fixed by having a
> separate wrapper for each type/subtype constructor.
> 
> Have I missed a method?
> 
> What I'd really like is to be able to specify the private fields as
> #:auto so they need not be given as constructor arguments but still have
> a guard procedure return them.  Something like:
> 
> (provide mystruct5
>         make-mystruct5
>         mystruct5-public)
> (struct mystruct5 (public [private #:auto])
>        #:constructor-name make-mystruct5
>        #:guard* (lambda (public name)
>                  (values public (get-new-private))))
> 
> This would allow me to completely control the private field within my
> module while not requiring bogus/ignored constructor arguments nor
> requiring wrappers.
> 
> (If there is nothing like this currently, and others think it would be
> good to have, I'd be willing to take a stab at implementing it.)
> 
> Thanks.
> 
> David
> 
> ____________________
>  Racket Users list:
>  http://lists.racket-lang.org/users


Posted on the users mailing list.