Clojure on the Google App Engine
fatvat.co.uk
fatvat.co.uk
Care to elaborate? I know Common Lisp's multimethods dispatch on class and object identity
(defmethod foo ((obj class-name)) ..)
(defmethod foo ((obj (eql object)) ..)
The first one dispatches if obj is of class "class-name", and the second dispatches if obj and object are EQL (i.e. strictly equal by value or pointer.) and this second one allows you to do very clean switch/case style dispatching on actual values.How does clojure do it?
In the example below we dispatch my-add based on a function of the two arguments. This function returns a bool that determines the function to call, but it could return anything that you could then use to define the method upon (e.g. a symbol).
(defmulti my-add (fn [x y] (and (string? x) (string? y))))
(defmethod my-add true [x y]
(str x y))
(defmethod my-add false [x y]
(+ x y))
(my-add 3 4) ==> 7
(my-add "3" "4") ==> "34" (defmethod my-add ((x integer) (y integer))
(+ x y))
(defmethod my-add ((x string) (y string))
(concatenate 'string x y))
CL-USER(8): (my-add 2 3)
5
CL-USER(9): (my-add "foo" "bar")
"foobar"
Keep in mind you're dispatching on both arguments; the MY-ADD generic function is created for you and it's lurking in memory. You can add :before, :after and :around methods, which will allow you to get a hold of both arguments BEFORE the dispatch method is applied and after in a serial fashion, or AROUND the method dispatch altogether. This allows for stuff like logging, debugging, tracing, method wrapping and augmentation for moving-target type protocols and designs, etc.Again you can dispatch on anything. Your dispatch function can return any value (a set, a hash-map, a vector, a list, a string, a number, etc.).
(defn new-dispatch [x y z] (meta y))
(defmulti my-multi new-dispatch)
(defmethod my-multi {:meta-key1 meta-val1} [x y z] ...)
(defmethod my-multi {:meta-key2 meta-val2} [x y z] ...)
This one dispatches on the metadata attached to the second argument.