with-redefs does not work for macros

1,114 views
Skip to first unread message

Vebjorn Ljosa

unread,
Apr 27, 2015, 12:34:14 PM4/27/15
to clo...@googlegroups.com
In one of my tests, I was trying to mock something (`clojure.tools.logging/warn`) that happened to be a macro. It had me puzzled for a while until I discovered that `with-redefs` resets the value of the vars after the body is executed, but does not reset the flag that says that the var is a macro:

$ lein repl
Clojure 1.6.0

user=> (defmacro foo [] `(prn "I am a macro"))
#'user/foo
user=> (clojure.test/function? 'foo)
false
user=> (with-redefs [foo (fn [] 42)])
nil
user=> (clojure.test/function? foo)
true
user=> (foo)
ArityException Wrong number of args (0) passed to: user/foo clojure.lang.AFn.throwArity (AFn.java:429)
user=> (foo 42 42)
(clojure.core/prn "I am a macro")

Is this a bug?

I looked at the source for `with-redefs-fn`, and the fix appears simple: record for each val whether it's a macro or not, and then call the `(setMacro)` method on the vars that should be macros after resetting their values.

Vebjorn

Vebjorn Ljosa

unread,
Apr 27, 2015, 2:03:43 PM4/27/15
to clo...@googlegroups.com
On Monday, April 27, 2015 at 12:34:14 PM UTC-4, Vebjorn Ljosa wrote:
In one of my tests, I was trying to mock something (`clojure.tools.logging/warn`) that happened to be a macro. It had me puzzled for a while until I discovered that `with-redefs` resets the value of the vars after the body is executed, but does not reset the flag that says that the var is a macro:

Granted, using `with-redefs` with a macro rarely makes sense because macroexpansion has to occur within the extent of `with-redefs` for the redefinition to have any effect. (I can't even think of an example where I would want to do that, so maybe `with-redefs` should emit a warning when it's being asked to redefine a macro.) But in any case, an attempt to use `with-redefs` on something that happens to be a macro should not mess up the root binding permanently.

Tiago Espinha

unread,
Oct 29, 2016, 9:01:19 AM10/29/16
to Clojure
Damn it, I got exactly the same thing. In my case when trying to mock the /error fun...ehem...macro :-)

There should definitely be some kind of warning or even an error. It doesn't make sense to mock macros since these are expanded at compile time.

Beau Fabry

unread,
Oct 31, 2016, 8:15:37 PM10/31/16
to Clojure
Not an answer to your question, but I usually just redefine clojure.tools.logging/log* instead for tests.

Tiago Espinha

unread,
Nov 1, 2016, 1:12:19 AM11/1/16
to Clojure

It's definitely good to mention. It's also what I ended up doing but didn't mention it in my answer :)

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/gCDnbREpdSg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages