[racket-dev] `make-struct-type-property` and impersonators

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Tue Jul 17 23:02:59 EDT 2012

This seems ok to me. I'm not convinced there are any useful guarantees
when an impersonable property has a guard, but I can see that there
could be a useful sanity check.

As you may already know: The primitive `make-struct-type-property'
procedure can't accept keyword arguments, because there are no keyword
arguments at that level, but you can make a wrapper that calls a
primitive variant.

At Tue, 17 Jul 2012 17:01:50 -0400, Asumu Takikawa wrote:
> Hi all,
> I mentioned an issue I had with struct type properties & impersonators
> in the promise/c thread, but I figured I should explain this in more
> detail.
> Currently, `make-struct-type-property` takes an optional argument which
> is the "guard" for the property. This guard is a procedure that checks
> the value coming from *users* of a property (via the `struct` form
> and #:property keyword). This is useful so that the implementor of a
> struct type property can rely on this guard invariant for whatever
> internal processing is needed.
> However, the guard can also be the 'can-impersonate symbol. In this
> case, there is no guard procedure and the struct type property accessor
> (the procedure actually used to obtain the stored value) can be
> impersonated.
> i.e., only one of these two are allowed:
>     (define-values (prop:widget widget? prop:widget-accessor)
>       (make-struct-type-property 'widget valid-widget?))
>     (define-values (prop:widget widget? prop:widget-accessor)
>       (make-struct-type-property 'widget 'can-impersonate))
> but not both.
> The issue is that there is a use case for having *both* impersonation of
> the accessor and a guard. The reason is that there are two interactions
> involved in a property: one interaction between the property implementor
> and the struct type creator, who provides the initial value using the
> `struct` form, and another interaction involving the client who accesses
> the property value in an existing structure instance.
> e.g.,
>   (struct a-widget (...)
>     #:property prop:widget some-widget) ; guarded by `valid-widget?`
>   vs.
>   (prop:widget-accessor w) ; not guarded, could be redirected
>                            ; by some impersonator
> The guard protects the property implementor in the former interaction,
> whereas the client is the one that is affected by any impersonation of
> the property. Since these two interactions aren't necessarily related,
> it's still useful to guard the property even if the property can be
> arbitrarily impersonated.
> One example where I needed this is to attach impersonator contracts
> (i.e., polymorphic contracts) to a method table in the generics
> implementation. The table is stored in a struct property and needs to be
> impersonatable for contracting.
> However, I don't want to introduce additional code that duplicates the
> sanity checking that the guard would guarantee for the initial methods
> provided by the implementor of an *instance* of a generic interface.
>    ***
> That was my summary of the problem. I propose to change the API a bit to
> make it more flexible: `make-struct-type-property` would take a keyword
> #:can-impersonate which will control impersonation entirely orthogonal
> to the guard argument (which would now be either #f or a procedure).
> I think this API would cover more of the possible use cases than what is
> currently available.
> One way to summarize the use of the guard is that with
> non-impersonatable properties, it is making a guarantee about what it is
> in the property. With impersonatable properties, it can only make a
> guarantee about the *initial* value of the property. The latter can
> still be useful though.
> Any thoughts?
> Cheers,
> Asumu
> _________________________
>   Racket Developers list:
>   http://lists.racket-lang.org/dev

Posted on the dev mailing list.