Clojure and me has moved.

Wednesday, May 28, 2008

Multimethods aren't magic (nor mutable)

This post has moved, go to its new location

What does this code display?

(defmulti foo first)
(def print-foo (comp println foo))
(defmethod foo :a [x]
"it's a 'a'!")
(print-foo [:a])

Nothing, it raises an error: it doesn't know what to do with the dispatch value :a. The value of foo is captured when comp is called.

The thing to keep in mind is that defmethod mutates the var, not the multimethod itself — which is of course immutable. The solution is to pass the var instead of the multimethod to comp:

(defmulti foo first)
(def print-foo (comp println #'foo))
(defmethod foo :a [x]
"it's a 'a'!")
(print-foo [:a]) ; prints "it's a 'a'!"

Update or maybe it's a code smell that you should use a macro instead of a function.

Update 2 Clojure's father (Rich Hickey) says : the correct thing to do is use the var.

Jumping to Javadocs from the REPL

This post has moved, go to its new location

(defn open-url [url]
(let [htmlpane (new javax.swing.JEditorPane url)]
(.setEditable htmlpane false)
(.addHyperlinkListener htmlpane
(proxy [javax.swing.event.HyperlinkListener] []
(hyperlinkUpdate [#^javax.swing.event.HyperlinkEvent e]
(when (= (.getEventType e) (. javax.swing.event.HyperlinkEvent$EventType ACTIVATED))
(if (instance? javax.swing.text.html.HTMLFrameHyperlinkEvent e)
(.. htmlpane getDocument (processHTMLFrameHyperlinkEvent e))
(.setPage htmlpane (.getURL e))
(catch Throwable t
(.printStackTrace t))))))))
(doto (new javax.swing.JFrame)
(setContentPane (new javax.swing.JScrollPane htmlpane))
(setBounds 32 32 700 900)

(defn javadoc [c]
(let [url (str ""
(.. c getName (replace \. \/) (replace \$ \.)) ".html")]
(open-url url)))

; usage:
; (javadoc Throwable) opens a window displaying Throwable's javadoc
; hint: (javadoc (class some-object))