Welcome! Please see the About page for a little more info on how this works.

0 votes
in Compiler by
It is possible to set! to fields of a defrecord even though they are final.

(defprotocol SetA (seta [x a]))
=> SetA
(defrecord X [a]
  (seta [this newa]
    ; Next line should error at compile time, does not.
    ; (However (set! a newa) does error correctly.)
    (set! (.a this) newa)))
=> user.X
(def x (->X 0))
=> #'user/x
=> #user.X{:a 0}
(seta x 1) ;; This should not run.
=> 1
=> #user.X{:a 1}

There are two issues here:

# The Clojure compiler does not detect that (set! (.a this) x) is assignment to a final field. This could be enhanced. Nicola Mometto has discovered why and believes he has a straightforward patch.
# The JVM bytecode verifier only performs the necessary final-assignment check on classfiles version 9 and above: https://bugs.openjdk.java.net/browse/JDK-8159215 (Clojure generates version 6 classfiles.) This is out of our hands.

*Approach:* make the compiler fail at compile time if trying to set! a field that's final

*Patch:* 0001-CLJ-2126-don-t-assign-final-fields.patch

1 Answer

0 votes
Reference: https://clojure.atlassian.net/browse/CLJ-2126 (reported by favila)