Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure: with-redefs doesn't work with clojure.core functions?

Tags:

clojure

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?

like image 485
user3535953 Avatar asked Apr 19 '14 06:04

user3535953


1 Answers

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.

like image 147
Michał Marczyk Avatar answered Sep 28 '22 05:09

Michał Marczyk