I've a question about with-redefs
. The following example doesn't work as expected.
In findmax
, clojure.core/max
is always called instead of the anonymous function in the
with-redefs
statement.
(defn findmax [x y]
(max x y))
(with-redefs (clojure.core/max (fn [x y] (- x y)))
(findmax 2 5))
When I make the following changes everything works as expected:
(defn mymax [x y]
(max x y))
(defn findmax [x y]
(mymax x y))
(with-redefs (my/max (fn [x y] (- x y)))
(findmax 2 5))
What am I doing wrong here?
max
is inlined by the Clojure compiler for arities greater than 1, so there is no reference to the Var #'clojure.core/max
in the compiled code and no way to change the behaviour of code fragments that use #'max
by changing its root binding. For arity 1, this does not happen:
(defn my-max [& args] :foo)
(with-redefs [clojure.core/max my-max] (max 0))
;= :foo
(with-redefs [clojure.core/max my-max] (max 0 1))
;= 1
(with-redefs [clojure.core/max my-max] (max 0 1 2))
;= 2
;; and so on
This is controlled by the entries at keys :inline
and :inline-arities
in the source of max
; see (source max)
.
There are quite a few automatically inlined functions in clojure.core
-- mostly the simple arithmetic operations. Client code is free to define new ones (by attaching explicit :inline
and possibly :inline-arities
metadata or by using definline
). The expected effect is similar to defining a macro, except an inlined function is still available for higher-order usage. It's important to note that the current implementation has its surprises (see CLJ-1227 in the Clojure JIRA, for example, and the more recent issues linked therefrom), so at the end of the day, for client code, careful use of regular macros and companion functions is likely to be preferable for the time being. In the future, inlined functions may well be replaced by regular functions paired with compiler macros -- this is the ClojureScript model.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With