1. Dispatch in Clojure Carlo Sciolla, Product Lead @ Backbase
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
2. (ns aot
(:gen-class))
(defn -main [& args]
(dorun
(map println (seq args))))
javap -c aot.class
A quick journey in function calling
We all learn to divide our code in functions, and invoke them when it’s
their time on the stage of data processing. We define units of
computations, ready to be executed.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
3. public static void main(java.lang.String[]);
[..]
4:! invokevirtual!#66;
[..]
26:!invokestatic!
#104;
29:!invokeinterface! #108, 2;
[..]
44:!invokespecial!#115; (defn -main [& args]
[..] (dorun
(map println (seq args))))
The JVM executes our code
We’ll leave it to the JVM to figure out which code to actually run upon
function call. It’s not always a straightforward job, and there are several
ways to get to the code.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
4. public static void main(java.lang.String[]);
[..]
4:! invokevirtual!#66;
[..]
26:!invokestatic!
#104;
29:!invokeinterface! #108, 2;
[..]
44:!invokespecial!#115;
[..]
[clojure.lang.RT] static public ISeq seq(Object coll)
Static dispatch
When there’s nothing to choose from, the compiler emits a static
dispatch bytecode. All calls will always result in the same code being
executed.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
5. public static void main(java.lang.String[]);
[..]
4:! invokevirtual!#66;
[..]
26:!invokestatic!
#104;
29:!invokeinterface! #108, 2;
[..]
44:!invokespecial!#115;
[..]
Dynamic dispatch
Most often the compiler can’t figure out the proper method
implementation to call, and the runtime will get its chance to
dynamically dispatch the call.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
6. * dispatch by arity
* object oriented inheritance
* multimethods
* custom is-a hierarchies
* protocols
The options at hand
Clojure provides a rich interface to dynamic dispatch, allowing
programmers to have control over the dispatch logic at different
degrees to find the optimal balance on the performance trade off scale.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
7. * dispatch by arity
* object oriented inheritance (defn sum-them
* multimethods ([x y] (+ x y))
* custom is-a hierarchies ([x y z] (+ x y z)))
* protocols
The good old arity
Being a dynamically typed language, Clojure only checks on the
number of arguments provided in the function call to find the right
implementation to call.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
8. * dispatch by arity (defn stringify [x]
* object oriented inheritance (.toString x))
* multimethods
* custom is-a hierarchies (stringify (HashMap.)) ; “{}”
* protocols (stringify (HashSet.)) ; “[]”
More than Java™
Thanks to Clojure intimacy with Java, object inheritance is easily
achieved. Thanks to Clojure dynamic typing, it also allows functions to
traverse multiple inheritance trees.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
9. (defn stringify*
[^HashMap x]
(.toString x))
* dispatch by arity
* object oriented inheritance
(stringify* (HashMap.))
* multimethods
=> “{}”
* custom is-a hierarchies
(stringify* (TreeMap.))
* protocols
=> “{}”
(stringify* (HashSet.))
=> ClassCastException
Forcing virtual dispatch to improve performance
Being a dynamic language has a number of benefits, but performance
isn’t one of them. To avoid reflection calls needed by default by the
dynamic dispatch you can use type hints.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
10. (defn dispatch-fn
[{:keys [version]}]
* dispatch by arity
version)
* object oriented inheritance
* multimethods
(defmulti multi-call
* custom is-a hierarchies
dispatch-fn)
* protocols
http://bit.ly/multi-tests
Full power
Multimethods allow you to define your own dispatch strategy as a plain
Clojure function. Their limit is the sky: they perform quite bad, and your
dispatch fn can’t be changed or extended in user code.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
11. (defmethod
multi-call ::custom-type
* dispatch by arity
[x] [...])
* object oriented inheritance
* multimethods
(derive java.util.HashSet
* custom is-a hierarchies
::custom-type)
* protocols
http://bit.ly/multi-tests
Inheritance à la carte
Java types hierarchies defined outside your code can be “altered” by
custom is-a? relationships created as needed. You can either use the
default hierarchy or use make-hierarchy to restrict its scope.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
12. (defprotocol Registered
(register [this]))
* dispatch by arity
* object oriented inheritance
(extend-type String
* multimethods
Registered
* custom is-a hierarchies
(register [this] [...]))
* protocols
http://bit.ly/proto-tests
Inheritance à la carte
Java types hierarchies defined outside your code can be “altered” by
custom is-a? relationships created as needed. You can either use the
default hierarchy or use make-hierarchy to restrict its scope.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
13. * never used when compiling pure Java
* moves type checking at run time
* the compiler doesn’t resolve the method
* user code to perform the dispatch
* eligible for JIT optimizations
http://bit.ly/headius-invokedynamic
Bonus track: invokedynamic
Java7 introduced a new bytecode instruction to help JVM languages
designers: invokedynamic. There’s a long standing discussion as which
benefits it can provide to Clojure.
DISPATCH IN CLOJURE | August 8, 2012 | @skuro
15. Thanks!
Amsterdam Clojurians
Carlo Sciolla
Product Lead
http://skuro.tk
@skuro
http://bit.ly/amsclojure
DISPATCH IN CLOJURE | August 8, 2012 | @skuro