Search code examples
clojureclojure-java-interop

How to write a public field of a Java object in Clojure?


This question answers how to read a public field from a Java object:

(let [p (java.awt.Point.)]
  (.x p))  ; <- returns 0

I thought I could write the field in a similar way:

(let [p (java.awt.Point.)]
  (.x p 42))

But I get the following error:

IllegalArgumentException No matching method found: x for class java.awt.Point
clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53)

Solution

  • This is covered in the Clojure - Java Interop:

    (set! (. instance-expr instanceFieldName-symbol) expr)
    

    Assignment special form.

    When the first operand is a field member access form, the assignment is to the corresponding field. If it is an instance field, the instance expr will be evaluated [and assigned to the corresponding instance field].

    Also note the use of '-' in resolving a field:

    If the second operand [of (. instance-expr member)] is a symbol starting with -, the member-symbol will resolve only as field access (never as a 0-arity method) and should be preferred when that is the intent..."

    Thus:

    (set! (. p -x) 42)
    

    Alternatively, the "preferred idiomatic forms for accessing field or method members" is slightly different, and this equivalency is shown in the macro expansion at the top of the page.

    (set! (.-x p) 42)