Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the point of defining something as dynamic when you don't need to define something as dynamic to with-redefs it?

Tags:

clojure

It seems to me that with-redefs can do everything that binding to a dynamic symbol can do, only it doesn't have the limitation of needing the ^:dynamic metadata. So when should I use one over the other?

like image 430
Daniel Kaplan Avatar asked Apr 01 '13 16:04

Daniel Kaplan


1 Answers

Aside from requiring the ^:dynamic metadata, binding also creates bindings that are only visible in the current thread, whereas the bindings made by with-redefs are visible in all threads. So, with-redefs is a very blunt tool and has the potential to affect other code running in the same VM. I've never seen with-redefs used outside of test code, nor should it be (at least in my opinion).

I would summarize the difference between the two as thus:

  • binding with ^:dynamic allows you to introduce a little bit of dynamic behavior in a controlled fashion. It's a good way of defining extension points in an API that let callers far up the call chain change the behavior of your code without having to explicitly pass parameters all the way through the call stack (some of which might not even be their code).
  • with-redefs is a free-for-all. It's useful in testing, e.g. for mocking out entire sub-systems when the function under test has lots of dependencies.

Declaring a var as ^:dynamic, together with the convention of using earmuffs to name dynamic vars (e.g. *my-dynamic-var*), has the added bonus that it's a self-documenting way of advertising to callers that that part of your code can be modified dynamically.

In summary: prefer ^:dynamic and binding when writing APIs and production code. Use with-redefs in testing, and as a last resort to dynamically alter the behavior of vars beyond your control that weren't declared ^:dynamic (and then, use with caution).

like image 130
Alex Avatar answered Sep 16 '22 16:09

Alex