A blog about software development and other software related matters

Blog Archive

Saturday, May 23, 2009

Newify your Object

Update a generous Anonymous has left a comment that the following special macro form does the same as the newify function that i present later on:

(def nested-object (-> GrandFather. Father. GrandSon.))

Feel free to skip this entry (unless your interested in an alternative implementation).

Instantiating large nested object graphs can be tedious in any language Clojure included:

(def nested-object
(new Grandson
(new Father
(new Grandfather))))

All those new methods call get old pretty quickly and are not DRY, to remedy this will take advantage on a cool property of Clojure Homoiconicity.
Homoiconicity basically means that the code is represented by a basic data structure of the language itself (lists in the case of Clojure), this means that manipulating the AST is easy as pie!
It would be nice if we could write something like the following:

(def nested-object
(def nested-object (newify '(Grandson (Father (Grandfather)))))

The newify function takes a nested list of objects & adds new before each object, post that the function evaluates the resulting list:

(defn newify [e] (eval (newify-imp e)))
; required since used before defined
(defn- newify-rest [e] )

(defn- newify-imp [e]
(let [add-new (partial cons 'new) add-rest (partial cons (first e))]
(if (not (empty? e))
(-> (newify-rest e) add-rest add-new) e)))

(defn- newify-rest [e]
(map #(if (list? %) (newify-impl %) %) (rest e)))

The newify-imp & newify-rest functions are mutually recursive, newify-imp adds the new symbol & the first list element to the result of the newify-rest function result, the newify-rest maps each list in the rest of the list to its newified value.

This implementation could be transformed into a recursive macro that will spare us from the list escaping:

(def nested-object (newify '(Grandson (Father (Grandfather)))))
; no escaping here
(def nested-object (newify (Grandson (Father (Grandfather)))))

Ill have to dig that option later on.


Anonymous said...

(def nested-object (-> GrandFather. Father. GrandSon.))

ronen said...

Cool iv never noticed this form before.

Ill update the article to spare time for those like myself :)