Update: Thank you everyone for your responses, but I seem to have made a bad choice using an embedded "def" in my example, which is throwing people off. This has nothing to do with def. The problem still occurs if I do not use a def. As to why I'm doing it this way -- honestly, I'm just trying to learn about macros, and this is just one of the ways that occurred to me. I'm just trying to understand how macros work. I may very well ultimately end up using a different mechanism. I also know that having multiple defs (including defmacros) for the same thing is considered bad practice, but it still seems to me this way should work.
I am re-factoring my examples:
When I write variations of a macro-generating macro in-line (with a simplified version of what I'm actually doing):
(do
(defmacro abc []
`(defmacro xyz []
;;(def x 7)))
(+ 7 1)))
(abc)
;;(xyz)
;;(spit "log.txt" (format "pass 1: x=%s\n" x ) :append false))
(spit "log.txt" (format "pass 1: results=%s\n" (xyz) ) :append false))
(do
(defmacro abc []
`(defmacro xyz []
;;(def x 8)))
(+ 8 1)))
(abc)
;;(xyz)
;;(spit "log.txt" (format "pass 2: x=%s\n" x ) :append true))
(spit "log.txt" (format "pass 1: results=%s\n" (xyz) ) :append false))
(do
(defmacro abc []
`(defmacro xyz []
;;(def x 9)))
(+ 9 1)))
(abc)
;;(xyz)
;;(spit "log.txt" (format "pass 3: x=%s\n" x ) :append true))
(spit "log.txt" (format "pass 1: results=%s\n" (xyz) ) :append false))
It gives me what I expect:
pre-refactor:
cat log.txt
pass 1: x=7
pass 2: x=8
pass 3: x=9
post-refactor:
cat log.txt
pass 1: results=8
pass 2: result=9
pass 3: result=10
But when I try to iterate using doseq, it only seems to give me one value:
(def int-lookup [7 8 9])
(doseq [i (range 3)]
(defmacro abc []
`(defmacro xyz []
;;(def x ~(int-lookup i))))
(+ 1 ~(int-lookup i))))
(abc)
;;(xyz)
;;(spit "log.txt" (format "pass %s: x=%s\n" i x) :append (if (= i 0) false true)))
(spit "log.txt" (format "pass %s: result=%s\n" i (xyz)) :append (if (= i 0) false true))
Output:
pre-refactor:
cat log.txt
pass 0: x=9
pass 1: x=9
pass 2: x=9
post-refactor
cat log.txt
pass 0: result=10
pass 1: result=10
pass 2: result=10
I've seen it give me all 7's, and all 8's too, but never mixed.
I've tried resetting the macro symbols in-between like so:
(ns-unmap *ns* 'xyz)
(ns-unmap *ns* 'x)
However, this make things even worse, sporadically generating:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: xyz in this context, compiling:(/tmp/form-init2424586203535482807.clj:5:5)
I'm sort of assuming the compiler is somehow optimizing the macro def or call, so it's only actually driving it once when using doseq. If this is the case, then how would you iterate over defmacro definitions and not have this happen? I intend to have about 15 iteration is my final solution, so I really don't want to have to in-line all definitions.
I'm pretty sure I know what's happening. It's a classic macro thing -- distinguishing between compile-time and run-time.
I think that when the do-seq is being compiled, the compiler needs to get something to put into the '(xyz) expression:
(spit "log.txt" (format "pass %s: result=%s\n" i (xyz)) <-- Compiler: what do I put here?....
I'm assuming it will come from the run-time value of 'xyz that is set by the prior defmacro:
(defmacro abc []
`(defmacro xyz [] <-- I'm assuming this version will be used
(+ 9 1)))
(abc)
while 'abc is known at the compile-time of the do-seq, the underlying macro 'xyz in the 'abc defmacro is only known at run-time. The compiler only knows about the 'xyz symbol set from my previous run, which returns 10. Thus the compiler statically inserts this expression, and ignores the runtime version, which why I see the same value each time.
Related
Let's say we need evaluate a number of clauses in a source file, e.g.
test.clj
#(def x 1)
#(def y 2)
#(def z 3)
Only the last evaluation shows up if we plainly use either clj or lein repl,
user => (load-file "test.clj")
3
We can surround each of them by println to show all of them,
test-with-println.clj
(println #(def x 1))
(println #(def y 2))
(println #(def z 3))
user => (load-file "test-with-println.clj")
1
2
3
nil
What are the better alternatives to avoid invasive printlns all over the source code while able to print out all the intended evaluations under the umbrella of REPLs?
#Solution
Thanks to tap> from the answer #Sean Corfield we can have desired results as follows,
pipe every wannabe printed out to tap>.
test-with-tap.clj
(-> #(def x 1) tap>)
(-> #(def y 2) tap>)
(-> #(def z 3) tap>)
REPLs will receive none of their outputs until tap> is turned on by add-tap.
user=> (load-file "test-with-tap.clj")
nil
user=> (add-tap #(def out (bound-fn* println)))
nil
user=> (load-file "test-with-tap.clj")
1
2
3
user=> (remove-tap out)
nil
user=> (load-file "test-with-tap.clj")
nil
tap> is probably what you're looking for - https://clojuredocs.org/clojure.core/tap%3E - This lets you send full Clojure values (not just strings) to any function registered as a listener, which can be something like Portal for example - https://github.com/djblue/portal - which is something I use all-day, every-day, but you can also use something as simple as println in add-tap to get every tap>'d value displayed.
The tap> calls can stay in your code, even in production, since there is next to no overhead to using them.
Although tap> returns a Boolean, you can use (doto expr tap>) to evaluate and return expr but still send the value to any tap listeners. tap> is a great debugging tool.
I haven't had a chance to play with tap> yet. My favorite over the years has been the spy family of functions in the Tupelo library. Specifically, check out spyx, spyx-pretty, and let-spy.
When calling a function that returns something the REPL prints the output. How to suppress this printing without resorting to temporarily adding nil as the last line in a function?
This is fairly easy to do. If, for instance, you have a function named f, then as you know, you can call it like this:
(f)
;; hello yes this is f
;;=> :huge
But if you want to ignore the output, you can do this instead:
(do (f) nil)
;; hello yes this is f
;;=> nil
You could also define an ignore function to do this for you if you feel like it:
(def ignore (constantly nil))
(ignore (f))
;; hello yes this is f
;;=> nil
I am looking for a way to determine if a function printed (using println or anything similar).
What I am trying to determine is if test-vars printed something or not.
The issue with this function is that it doesn't return anything, but only print things when errors got issues, but I want to know if it succeeded or not and the only way I see to know it is to check if it printed something or not.
Even better would be a way to "intercept" what is going to out and to put it in a variable.
After the comments from #lee and #leetwinski I tried the following:
(deftest test-1
(testing
(is (= 1 2))))
Then I tried to run that test using:
(let [printed (with-out-str (test-vars [#'test-1]))]
(print (str "Printed size: " (count printed))))
But here is what I got:
FAIL in (test-1) (form-init505699766276988020.clj:103)
expected: (= 1 2)
actual: (not (= 1 2))
Printed size: 0
nil
So, what test-vars outputs has been outputted anyway. Then printed was empty.
in addition to #Lee's answer: in general you could just rebind *out* to any other writer you want:
temporary binding:
user> (binding [*out* (java.io.StringWriter.)]
(println 101)
(str *out*))
"101\n"
is just an analogue to with-out-str
thread-local binding:
user> (set! *out* (java.io.StringWriter.))
#object[java.io.StringWriter 0x575e6773 ""]
user> (println 123)
nil
user> (str *out*)
"123\n"
here we rebind the *out*, for the current thread (and for all the threads, spawned from it, AFAIK).
You can use with-out-str which intercepts printed values and collects them into a string:
(let [printed (with-out-str (test-vars))]
...)
For example, as in the example here,
=> (-> "a b c " .toUpperCase (.replace "A" "X") (.split " ") first)
=> "X"
I'd like to be able to do something like
=> (-> ^String "a b c " .... etc etc
to avoid the reflection penalties, esp. in interfacing with java code.
It is possible to type hint expressions using the -> macro. While the following uses reflection:
(set! *warn-on-reflection* true)
(def s "1")
(-> s .toString)
;; Reflection warning, NO_SOURCE_PATH:1:1 - reference to field toString can't be resolved.
;;= "1"
This doesn't:
(-> ^String s .toString)
;;= "1"
Maybe if you share a specific expression where you are finding it hard or impossible to type hint we can help you better.
There is a known situation where the type hint attached to the macro's &form expression is discarded, see this JIRA ticket Macroexpansion discards &form metadata. Maybe this is what you are seeing?
Yes, it is possible.
If you need to type-hint the initial argument to ->, you can do it directly, either inside or outside the -> form:
(-> ^String (foo) .toUpperCase)
(let [^String f (foo)]
(-> f .toUpperCase))
There will be no reflection in either case.
If the value that you wish to type-hint arises at an intermediate step in the -> chain, then you can type-hint it by putting the type hint on the -> step:
;; note the type hints on identity and (identity)
(-> ^String (foo) .toUpperCase ^String identity .toLowerCase)
(-> ^String (foo) .toUpperCase ^String (identity). toLowerCase)
Again, there will be no reflection in either case.
(Tested at a 1.7.0-alpha5 REPL.)
Well, in your case at least, there are no reflection penalties.
user=> (set! *warn-on-reflection* true)
true
user=> (-> "a b c " .toUpperCase (.replace "A" "X") (.split " ") first)
"X"
If you want to be even more sure:
user=> (def i 23)
#'user/i
user=> (.toString i)
Reflection warning, NO_SOURCE_PATH:1:1 - reference to field toString can't be resolved.
"23"
I am trying to better understand listing 13.3 in The Joy of Clojure. It is a macro that generates other macros (much like how primitive array functions are implemented in Clojure 1.4).
I want to write a macro that, when run, simply prints the suffix of the generated macro. i.e.
user=> (nested-macro joe)
user=> (nested-macro-named-joe)
hello from joe
nil
I am having trouble making this work.
Here is what I've tried:
Attempt 1
(defmacro nested-macro [name]
`(defmacro ~(symbol (str "nested-macro-named-" name))
[]
`(println "hello from " ~name)))
Output:
hello from #<core$name clojure.core$name#502c06b2>
Attempt 2
(defmacro nested-macro [name]
(let [local-name name]
`(defmacro ~(symbol (str "my-custom-macro-named-" ~local-name))
[]
`(println "hello from " ~local-name))))
Error
IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote clojure.lang.Var$Unbound.throwArity (Var.java:43)
Attempt 3:
(defmacro nested-macro [name]
(let [local-name name]
`(defmacro ~(symbol (str "nested-macro-named-" name))
[]
`(println "hello from " ~(symbol local-name)))))
Compiler Error:
CompilerException java.lang.RuntimeException: No such var: joy.dsl/local-name
Just for the heck of it, I've also tried adding # to the local variables, with similar results as above but with "auto" names, such as local-name__1127__auto__ I don't see that being as part of the solution, however.
How can I make this work?
To know what is going wrong with macros I always use macroexpand-1.
From your first example:
(macroexpand-1 '(nested-macro joe))
Results in:
(clojure.core/defmacro nested-macro-named-joe []
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote clojure.core/println))
(clojure.core/list "hello from ")
(clojure.core/list clojure.core/name))))
If you look at the last param, it shows that you are using clojure.core/name, which probably is not what you want, as you actually want the parameter named "name".
To fix it, just add another unquote to the name param, but as the name param is actually a symbol, what you really want is to get the name of it as in:
(defmacro nested-macro [the-name]
`(defmacro ~(symbol (str "nested-macro-named-" the-name))
[]
`(println "hello from " ~~(name the-name))))