Mark Needham

Thoughts on Software Development

clojure/Java Interop: The doto macro

without comments

I recently wrote about some code I’ve been playing with to import neo4j spatial data and while looking to simplify the code I came across the doto macro.

The doto macro allows us to chain method calls on an initial object and then returns the resulting object. e.g.

(doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
-> {a=1, b=2}

In our case this comes in quite useful in the function used to create a stadium node which initially reads like this:

(defn create-stadium-node [db line]
  (let [stadium-node (.. db createNode)]
    (.. stadium-node (setProperty "wkt" (format "POINT(%s %s)" (:long line) (:lat line))))
    (.. stadium-node (setProperty "name" (:stadium line)))
  stadium-node))

Here we first create a node, set a couple of properties on the node and then return it.

Using the macro it would read like this:

(defn create-stadium-node [db line]
  (doto (.. db createNode)
    (.setProperty "wkt" (format "POINT(%s %s)" (:long line) (:lat line)))
    (.setProperty "name" (:stadium line))))

We can also use it to close the transaction at the end of our function although we don’t actually have a need for the transaction object which gets returned:

# the end of our main function
   (.. tx success)
   (.. tx finish)

…becomes…

(doto tx (.success) (.finish))

As far as I can tell this is pretty similar in functionality to the Object#tap function in Ruby:

{}.tap { |x| x[:a] = 1; x[:b] = 2 }
=> {:a=>1, :b=>2}

Either way it’s a pretty neat way of simplifying code.

Be Sociable, Share!

Written by Mark Needham

March 17th, 2013 at 8:21 pm

Posted in Clojure

Tagged with , ,