Clojure’s doto vs -> for GUI development

I’ve been reading the source code of a Clojure snippet in Is this a closure? If so, why? that eventually made me wonder why people keep using doto over the -> (“threading”) macro.

You can find a bit information on the -> macro in Understanding the Clojure -> macro or fire up Clojure’s REPL and…

user=> (doc doto)
-------------------------
clojure.core/doto
([x & forms])
Macro
  Evaluates x then calls all of the methods and functions with the
  value of x supplied at the front of the given arguments.  The forms
  are evaluated in order.  Returns x.

  (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))

user=> (doc ->)
-------------------------
clojure.core/->
([x] [x form] [x form & more])
Macro
  Threads the expr through the forms. Inserts x as the
  second item in the first form, making a list of it if it is not a
  list already. If there are more forms, inserts the first form as the
  second item in second form, etc.

When I first met the -> (and ->>) macro I became a big fan of it – it’s very simple, elegant and, well, a bit crazy in its form. It’s definitely something you won’t find in Java and hence a bit magical for Java programmers.

I’ve lately been interested in using Clojure for a GUI application development and kept stumbling upon doto whenever the Java Swing API was used. It’s the very moment when I used to learn the most – when I’m faced with an issue that troubles me for so long that once the time to sort it out comes (i.e. it’s not longer a wish but a must to find out the answer), a short session quickly turns out enough to grasp the merit and the experience stays in my memory forever (it’s when doing later means staying longer).

Before I answer the question about the difference between doto and ->, have a look at the REPL session below and try to figure it out yourself.

user=> (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
#<HashMap {b=2, a=1}>
user=> (-> (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
NullPointerException   clojure.lang.Reflector.invokeInstanceMethod (Reflector.java:26)
user=> (.printStackTrace *e)
java.lang.NullPointerException
	at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:26)
	at user$eval35.invoke(NO_SOURCE_FILE:23)
	at clojure.lang.Compiler.eval(Compiler.java:6201)
	at clojure.lang.Compiler.eval(Compiler.java:6168)
	at clojure.core$eval.invoke(core.clj:2680)
	at clojure.main$repl$read_eval_print__5619.invoke(main.clj:179)
	at clojure.main$repl$fn__5624.invoke(main.clj:200)
	at clojure.main$repl.doInvoke(main.clj:200)
	at clojure.lang.RestFn.invoke(RestFn.java:422)
	at clojure.main$repl_opt.invoke(main.clj:266)
	at clojure.main$main.doInvoke(main.clj:361)
	at clojure.lang.RestFn.invoke(RestFn.java:437)
	at clojure.lang.Var.invoke(Var.java:409)
	at clojure.lang.AFn.applyToHelper(AFn.java:169)
	at clojure.lang.Var.applyTo(Var.java:518)
	at clojure.main.main(main.java:37)
nil

Did it help you out in some way? Have you already figured out the answer? Can you explain why the above blew up? Honestly, it took me a longer while before I could spot the real cause of the exception.

Here’s what worked for me and helped me find the cause.

user=> (def hm (java.util.HashMap.))
#'user/hm
user=> hm
#<HashMap {}>
user=> (.put hm "a" 1)
nil

When I saw the last nil, it was when I experienced the “Aha!” moment (!) The return value of the (.put) function call is nil, so threading with the -> macro won’t work as it passes the value on to the following form and the value is nil. The doto macro doesn’t exhibit the issue as it calls the following forms on the very first input parameter. That’s easy now, isn’t it?

Be Sociable, Share!
This entry was posted in Languages.

4 Responses to Clojure’s doto vs -> for GUI development

  1. Martin Valjavec says:

    Hi, Jacek!
    I do not think people are “using doto instead of the threading macro” since they are not related: The threading macro is, instead, related to the .. macro which is intended for Java interop, i.e. chaining of Java method calls while the threading macro chains calls of Clojure functions. In both cases the result of a previous call is fed as an argument into the next call.
    The doto macro calls several methods on the SAME object and was originally only usable for Java interop: You had to omit the . in the method names and it was assumed they had to be methods, not Clojure functions! In later versions you need to prepend the . before each name if it is a Java method name so that, without a . prepended, you can now refer to Clojure functions and use doto for these, too. Of course that means that programmers who used doto in earlier versions had to change their code when upgrading.
    So doto performs a “cascaded call” (like Smalltalk with its ” ; operator” – they call it a “message cascade” or “cascaded message”) while .. and -> are performing “chained” or “nested” calls (I think the notion of nesting is clear). With this simple picture we can see the difference without looking at stacktraces in REPL sessions, so this is how I would explain it to beginners (and to myself, since I’m also in this lot ;-)
    Thus chaining will only evaluate to the same result as doto if, accidentally, the methods always return their receiver (or the functions always return their first argument).
    If Java’s setter methods always returned their receiver (which is, alas, not idiomatic in Java) it would be easier to initialize such objects without the need for a doto macro: chained calls are easy in Java but there’s no simplified syntax for cascading.

  2. Pingback: Experiencing beauty of thread macro in Clojure | Japila :: verba docent, exempla trahunt

  3. gregdetre says:

    I had the exact same question, and your explanation was hugely helpful. Thank you!

  4. Pierre Masci says:

    So basically, -> is good for representing a chain of transformations on a value, while (doto) is better suited when dealing with a mutable object, as you will want to call methods on this object repeatedly. Right?

Leave a Reply

%d bloggers like this: