This morning I wrote some code which looked like:
(reduce (fn [acc x]
(reduce (fn [acc y]
(reduce f acc y)) acc x)) init xs)
(it was slightly more complex with some filtering and destructuring thrown in for good measure).
I wasn’t happy with those nested reduces and it occured to me that I could refactor it to use a single one:
(reduce f init (for [x xs, y x, z y] z))
Now that reads better!
- What’s wrong with this code
(do (defmacro foobar [x] (doto x println)) (foobar (+ 1 1)))
?
- Nothing.
- Run it again.
- The first time,
foobar
is treated as a function (its argument has been evaluated) because foobar
is unknown before the whole top-level expression is compiled.
The second time, the var named foobar
preexists and is a macro, (foobar (+ 1 1))
is expanded.
This behaviour bit me while using with-test
to test macros. It’s the kind of bug that goes unnoticed while developing incrementally and evaluating in the same REPL, it was waiting for me to start a fresh REPL.
I was trying to write a restartable parser in Clojure when it occured to me that I was doing it wrong by not using clojure.zip to build the parse tree.
Update: follow-up
I thought that there was some kind of doall
in apply
to force evaluation of the arguments seq but it’s not the case when the applied function is variadic.
In the previous post, there were several mistakes. They are all fixed by now, except one:
(defn top [n h]
(take n (sort #(- (val %2) (val %1)) h)))
Yup, this code is buggy: it is intended to sort hash entries by descending val order (values are numbers) and it breaks on large data sets.
With large data sets, some values get big and doesn’t fit into an int anymore while some stay small thus the difference of such two numbers doesn’t fit into an int while Comparator.compare must return an int: overflow.
Here is one way to fix that:
(defn top [n h]
(take n (sort #(.compare clojure.lang.Numbers (val %2) (val %1)) h)))
I have hope that there will be a better way to fix that in a near future.
(defn top [n h]
(take n (sort #(compare (val %2) (val %1)) h)))
This is an old post, refers to
Clojure.org for details on how gen-class works now.
Although generating a servlet class is a canonical example of using Clojure’s genclass I had never do this — I’ve used a handmade ClojureServlet which predates genclass.
Today, as I was starting a new project, I decided to get rid of this legacy ClojureServlet and to generate a brand new one.
Right at the end of genclass.clj there’s the following example:
(clojure/gen-and-save-class "/Users/rich/dev/clojure/gen/"
'org.clojure.ClojureServlet
:extends javax.servlet.http.HttpServlet)
I changed the path, created the directory structure (gen-and-save-class
doesn’t create the org/clojure/
directories) and ran this code (NB: servlet-api.jar must be on the classpath). Et voilà, org/clojure/ClojureServlet.class
!
Now to the Clojure code, I created org/clojure/ClojureServlet.clj
to define the methods and launched Tomcat to test the servlet. It crashed in the init
method.
In org/clojure/ClojureServlet.clj
I have:
(in-ns 'org.clojure.ClojureServlet)
(clojure/refer 'clojure)
(defn init [this config]
;censored
)
Cause: init does not call super.init(ServletConfig) as GenericServlet mandates it. Hopefully GenericServlet provides an init() which is easier to override, so I changed the code to:
(in-ns 'org.clojure.ClojureServlet)
(clojure/refer 'clojure)
(defn init-void [this]
;censored, again
)
which override only the init method taking no arguments. The bug was fixed.
To override a specific signature, define a var named methodName-firstArgClassName-secondClassName...
(e.g. init-ServletConfig) or methodName-void
if no arguments.
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
.