[racket-dev] A tricky chaperone puzzle

From: Sam Tobin-Hochstadt (samth at cs.indiana.edu)
Date: Thu Jul 24 15:45:18 EDT 2014

Consider the following module:

(module m racket
  (struct x [a])
  (define v1 (x 'secret))
  (define v2 (x 'public))
  (provide v1 v2)
  (provide/contract [x-a (-> x? (not/c 'secret))]))

It appears that this ensures that you can't get 'secret. But, it turns
out that I can write a function outside of `m` that behaves like `x-a`
without the contract:

(require (prefix-in m: 'm))

(define (x-a v)
  (define out #f)
  (with-handlers ([void void])
    (m:x-a (chaperone-struct v m:x-a (λ (s v) (set! out v) v))))

Now this works:

(displayln (x-a m:v1)) ;; => 'secret

The problem is that `m:x-a` is treated as a
`struct-accessor-procedure?`, which is a capability for accessing the
a field, even though it's a significantly restricted capability.

There are a couple possible solutions I've thought of:

1. Require a non-chaperoned/impersonated accessor.
2. Actually use the chaperoned/impersonatored accessor to get the
value out instead of the underlying accessor.

1 is a little less expressive. But note that 2 means that you have to
only allow chaperoned procedures with `chaperone-struct`, and imposes
significant complication on the runtime.

I favor 1.


Posted on the dev mailing list.