12

I would like to understand difference between with-redefs and with-redefs-fn.

Concrete examples would be great to understand the fns behaviours.

Ertuğrul Çetin
  • 5,131
  • 5
  • 37
  • 76

2 Answers2

16

They're basically the same, the main difference is that with-redefs lets you write out the body explicitly (like in a let), while with-redefs-fn requires a function as the argument, so you may need to wrap what you want in a lambda. Additionally, with-redefs lets you provide bindings using a vector (again, like let), while with-redefs-fn wants a map. I'd argue that both of these differences are just superficial.

e.g.

(with-redefs [http/post (fn [url] {:body "Goodbye world"})]
  (is (= {:body "Goodbye world"} (http/post "http://service.com/greet"))))

vs

(with-redefs-fn {#'http/post (fn [url] {:body "Goodbye world"})}
      (fn [] (is (= {:body "Goodbye world"} (http/post "http://service.com/greet")))))

In fact, with-redefs is defined in terms of with-redefs-fn, and basically just wraps the body in an anonymous function before passing everything to with-redefs-fn: https://github.com/clojure/clojure/blob/e3c4d2e8c7538cfda40accd5c410a584495cb357/src/clj/clojure/core.clj#L7404

Alejandro C.
  • 3,771
  • 15
  • 18
7

I would ignore with-redefs-fn and use only with-redefs since it is simpler and has the same abilities. Also, beware that the notation #'http/post requires you to use the var for http/post, not the function itself.

For a description of how a Clojure var works, please see this question: When to use a Var instead of a function? It is similar to a C pointer.

In clojure, when you see foo, it is a symbol. When you see #'foo, it is a shortcut for (var foo) which is a "special form" (i.e. a Clojure built-in, not a regular function), which returns the var that foo points to. The var in turn points the the value of foo.

Community
  • 1
  • 1
Alan Thompson
  • 29,276
  • 6
  • 41
  • 48