[racket] `immutable?` for `struct`s?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Sat Jan 25 18:07:46 EST 2014

> flaw: If an immutable struct is derived from a mutable one, my
> predicate will (as written) incorrectly report it as immutable.
> Instead I need to walk the chain of super-types, and check that all
> are immutable. I'll work on this more...

Here's where I ended up for now.

Although I don't understand how/when/why skipped? = #t would arise,
I'm pretty sure that if it does arise, I can't make any assertion
about immutability and should err on the side of saying "no".

Will sleep on this. Would welcome feedback if anyone has any.

;; As documented, `immutable?` does not work with `struct`s. Define a
;; predicate that does:
(define (immutable-struct? v)
  (define-values (st skipped?) (struct-info v))
  (and (not skipped?) ;unless most-specific type, can't assert immutability
       (immutable-struct-type? st)))

(define (immutable-struct-type? st)
  (define-values (name init-field-cnt auto-field-cnt
                  accessor-proc mutator-proc
                  immutable-k-list
                  super-type skipped?) (struct-type-info st))
  ;; A struct-type is immutable if all its fields are immutable, AND
  ;; all its super struct-types are immutable.
  (and (not skipped?) ;unless most-specific type, can't assert immutability
       (= (+ init-field-cnt auto-field-cnt)
          (length immutable-k-list))
       (or (not super-type)
           (immutable-struct-type? super-type))))

(module+ test
  (struct mutable (fld) #:mutable #:transparent)
  (define m (mutable 0))
  (check-false (immutable-struct? m))

  (struct mutable:immutable mutable (fld2) #:transparent)
  (define m:i (mutable:immutable 0 1))
  (check-false (immutable-struct? m:i))

  (struct immutable (fld) #:transparent)
  (define i (immutable 0))
  (check-true (immutable-struct? i))

  (struct immutable:immutable immutable (fld2) #:transparent)
  (define i:i (immutable:immutable 0 1))
  (check-true (immutable-struct? i:i)))

Posted on the users mailing list.