[racket] dynamically auto-initialized private struct fields
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