9

How do I factor code setting many different fields in a Java object? I would like to factor

(set! (. employee name) "Chris")
(set! (. employee age) 100)
(set! (. employee salary) 5000)

to

(doseq [field '((name "Chris") (age 100) (salary 5000))]
  (set! (. employee (first field)) (second field)))

However this won't work because the period is a macro, and tries to evaluate (first field) literally. By the way, I understand that setting fields is not good practice. I need to inter-operate with legacy code.

2 Answers 2

8

Try to use setters - but if you have no choice and really need to factor this out, a macro like this would do:

(defmacro set-all [object & fields-and-values]
  (let [obj-sym (gensym)] 
    `(let [~obj-sym ~object]
        ~@(for [[field value] (partition 2 fields-and-values)]
           `(set! (. ~obj-sym ~field)
                  ~value)))))

The gensym is needed in case the expression yielding object has any side effects.

Example usage:

user> (def p (java.awt.Point.))
#'user/p
user> (set-all p x 4 y 5)
5
user> p
#<Point java.awt.Point[x=4,y=5]>
Sign up to request clarification or add additional context in comments.

Comments

6

You might try:

(defmacro set-all! [obj m]
    `(do ~@(map (fn [e] `(set! (. ~obj ~(key e)) ~(val e))) m) ~obj))

Example:

(def a (java.awt.Point.))
(set-all! a {x 300 y 100})

Macroexpand-all:

(do (set! (. a x) 9)
    (set! (. a y) 7)
    a)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.