[racket] Struct & match magick

From: Sam Tobin-Hochstadt (samth at cs.indiana.edu)
Date: Tue Aug 19 09:35:48 EDT 2014

On Tue, Aug 19, 2014 at 8:32 AM, Roman Klochkov <kalimehtar at mail.ru> wrote:
> #lang racket
> (require (for-syntax racket racket/struct-info))
> (struct foo (a b))
> (set! foo-a (let ([old foo-a])
>                           (λ (x) (displayln x) (old x))))
> (define t (foo 1 2))
> (displayln "Before change")
> (match t [(foo a b) a])

In this code, `match` looks at `foo`, and sees that it's definitely a
struct descriptor created by `struct`, and so that it knows that `t`
will really be an instance of `foo`. Then it generates code that uses
`unsafe-struct-ref` to extract the fields. That's why it never uses
the modified `foo-a`.  To check this, it uses the
`checked-struct-info?` predicate.

> (let-syntax ([foo (extract-struct-info (syntax-local-value #'foo))])
>    (displayln "After change")
>    (match t [(foo a b) a]))

In this code, `match` can't be sure that `foo` refers to a real
struct, so it just treats the struct info as describing some
procedures and a predicate, and it generates the "obvious" code, which
calls `foo-a`, which you've modified.

I could change `match` so that it also uses
`variable-reference-mutated?` for all of the identifiers where it uses
checked struct info, and so behaves the same in both cases. However,
I'd prefer to reject the first program instead, by hiding `foo-a`
behind a macro that rejects assignment.


Posted on the users mailing list.