I get some weird behaviour when checking if a symbol can be resolved.
user=> ok
CompilerException java.lang.RuntimeException: Unable to resolve symbol: ok in this context, compiling:(NO_SOURCE_PATH:0)
user=> (resolve 'ok)
nil
user=> (if (resolve 'ok) "bla" (def ok 'ok))
"bla"
user=> ok
#<Unbound Unbound: #'user/ok>
user=> (def ok 'ok)
#'user/ok
user=> ok
ok
Can anyone tell me where this might come from? Is this behaviour intended?
(def ok "whatever") creates a variable named ok at compile time. The compiler scans the whole form to compile it, discovers that you will be defining a var named ok, and creates it for you (with no binding), before your form is actually executed. When the def form is actually executed, the runtime value of the expression will be assigned to the var user/ok. In your example, this never happens, because the var has already been created, and the if branch goes the other way.
Using bound? as a substitute is a terrible idea, as it tests something quite different: whether the named var (which must exist) has a binding, either permanent or thread-local.
Since I only use it inside a macro I now use it as follows
(defmacro bla [x]
(if (resolve x) x `(def ~x '~x)))
And now it works since def is inside the quoted form and evaluated after resolve.
Related
In Clojure, are the variables defined through with-local-vars accessible through closure?
Consider the below example:
(defn foo []
(with-local-vars [bar 10]
(fn [] #bar)))
((foo))
Result is the following:
#object[clojure.lang.Var$Unbound 0x131f68d8 "Unbound: #<Var: --unnamed-->"]
(Instead, I was expecting to get 10.)
C.f. with the following:
(defn foo []
(with-local-vars [bar 10] #bar))
(foo)
Result: 10.
Based on the documentation, it is not clear to me, if it is valid to use local vars in Clojure as above, but I would suspect the answer is no. Can you please confirm this (or refute, and explain what I'm doing wrong in the first example)? And if my supposition is clear (i.e., that local vars cannot be used in the closure), then explain what is the reason for that?
EDIT: for the records, this is the problem I was trying to solve.
The documentation for with-local-vars doesn't seem particularly clear here. It just says it creates thread-local bindings for the variables, but doesn't say anything about what happens to them when you exit the with-local-vars scope.
In contrast, the with-bindings documentation explicitly says that the thread-local bindings are popped when leaving that scope.
If you look at the source code, you can see that both with-local-vars and with-bindings are implemented using the same basic mechanisms (pushThreadBindings and popThreadBindings), which suggests they should have almost identical behavior.
So yes, you're right, you cannot expect the with-local-vars values captured in a closure to work outside of the with-local-vars scope. However, Clojure provides the bound-fn mechanism specifically for building this type of closure, capturing all of the current thread-local bindings:
(def foo (with-local-vars [bar 10] (fn [] #bar)))
(foo)
; => #object[clojure.lang.Var$Unbound 0x60063e12 "Unbound: #<Var: --unnamed-->"]
(def baz (with-local-vars [bar 10] (bound-fn [] #bar)))
(baz)
; => 10
I would like to execute some Clojure code that depends upon a certain var, but only if that var is defined. As a simplified example, the body of the if form should only be executed if sym is defined:
(if (resolve 'sym) (println sym))
Unfortunately, this doesn't work. If sym is not defined, the compiler still tries to resolve it and throws:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: sym in this context
From reading Rich Hickley's comment here, I gathered that this behavior is due to Clojure's use of (mostly) single-pass compilation. However, as much sense as that makes, it obviously results in undesirable behavior in this case.
I can get around the problem by forcing the symbol resolution to happen at runtime:
(if (resolve 'sym) (println (deref (resolve 'sym))))
But this is an undesirable hack. Is there a better way, or is it not possible with Clojure's read-eval model?
(Why do I need to do this? I have multiple composable profiles defined in my profiles.clj. One of them is for vinyasa, which allows me to inject various functions into the conveniently accessible . namespace. Others load various other utility libraries. In the profiles for those other utility libraries, I want to use vinyasa to inject the most important functions, but only if vinyasa is loaded. I am currently using a variation of the hack above.)
The approach recommended by #Michiel with when-let is the best way to solve this problem. Importantly, you can make the conditionality almost completely transparent by using let's ability to shadow an existing binding:
(when-let [foo (resolve 'foo)]
(foo))
;;=> nil
(defn foo []
:bar)
(foo)
;;=> :bar
(when-let [foo (resolve 'foo)]
(foo))
;;=> :bar
(defn get-when-var-defined [sym]
(when-let [var-for-sym (resolve sym)]
#var-for-sym))
(get-when-var-defined 'foo) ;;=> nil
(def foo 1)
(get-when-var-defined 'foo) ;;=> 1
Here's snippet:
(defmacro produce-constantly-fn []
(constantly :value))
(defmacro produce-fn []
(fn [& args] :value))
(defn test-fn []
((produce-fn)))
;; during evaluation of form below it throws:
;; java.lang.IllegalArgumentException
;; No matching ctor found for class clojure.core$constantly$fn__4614
(defn test-constantly-fn []
((produce-constantly-fn)))
Why last function cannot be compiled? The snippet can be considered as some sort macros abuse, but anyway...
I assume you defined your macro body without quoting and you are curious why it results in such a weird error message. If you really meant to define a macro for calling (constantly :value) then you should use quoting and it will work:
(defmacro produce-constantly-fn []
`(constantly :value))
(defn test-constantly-fn []
((produce-constantly-fn)))
=> #'user/test-constantly-fn
(test-constantly-fn)
=> :value
Now going back to your case without quoting. It looks really interesting and mysterious so I did some digging. These are my findings:
When you define a macro:
(defmacro produce-constantly-fn []
(constantly :value))
it will just create a function named produce-constantly-fn and mark it as a macro (it's still a Clojure function).
When you look into the implementation of constantly you will find (docs and meta omitted):
(defn constantly [x]
(fn [& args] x))
Under the hood it will compile to a closure object which will implement IFn and will have a single constructor parameter to close over x parameter. Something like this in Java code:
public class clojure.core$constantly$fn__4614 {
private final Object x;
public clojure.core$constantly$fn__4614(Object x) {
this.x = x;
}
public Object invoke(...) {
return x;
}
// other invoke arities
}
Now when you have following sexp:
(defn test-constantly-fn []
((produce-constantly-fn)))
I noticed that Clojure reader evals (produce-constantly-fn) which should return just a function object (produced by calling (constantly :value)) but I found in debugger that it produces clojure.core$constantly$fn__4614. symbol instead (notice the . at the end of the symbol - it is a Java interop form for calling a constructor). It looks like a function object/value gets somehow converted to a symbol representing its constructor call. I could find that the function value gets converted into Compiler$InvokeExpr object containing references to the compiled class name which is probably somehow converted into the symbol.
The reader tries to resolve clojure.core$constantly$fn__4614. further. It gets transformed by the reader into a call to clojure.core$constantly$fn__4614clojure.core$constantly$fn__4614 class constructor with no parameter.
As you have seen above the constructor of that class requires exactly one constructor thus the compilation fails (in clojure.lang.Compiler.NewExpr constructor body) with:
java.lang.IllegalArgumentException: No matching ctor found for class clojure.core$constantly$fn__4614
I am not sure why the Clojure reader transforms the function value to a symbol with constructor call interop form and causing such behaviour thus I presented only the direct cause of the error message and not the root cause why your code doesn't work. I guess it might be a bug or it was a conscious design decision. From the macro authors it would be better to fail fast and learn that the return value of a macro is not a valid code data but on the other hand it might be very difficult or impossible to determine if the returned data is a valid code or not. It's worth checking on Clojure mailing list.
I think what is going on is: macros resolve before functions.
So if you call macroexpand-1 on the function you get:
(def test-constantly-fn (clojure.core/fn ([] ((produce-constantly-fn)))))
Thus ((produce-constantly-fn)) is called before function and gives listed error.
I use simulation-style tests in to ensure that my entire application works correctly. The core Clojure test library is used for tests, executed via Leiningen. As the -main function runs, it defines symbols for later use within its logic. The problem is that if I accidentally use a symbol created in one -main test but never defined in the current -main test, it still has a value. I would expect to get an error that the symbol is undefined, but it seems my test environment is somehow sharing state between deftest executions. How can I deal with this? Move all my convenience-driven symbol definitions to a let statement?
If you are def-ing global vars inside your function, that's generally considered bad practice and reason enough to use let as you suggest instead.
However, you can capture a snapshot the mappings of your namespace.
(def ns-snapshot (ns-map *ns*))
So that after you intern symbols
(def foo 1)
(def bar 2)
You can determine the additions
(reduce dissoc (ns-map *ns*) (keys ns-snapshot))
;=> {bar #'so.core/bar, foo #'so.core/foo}
And un-map them
(doseq [[k v] (reduce dissoc (ns-map *ns*) (keys ns-snapshot))] (ns-unmap *ns* k))
So that you'll get the desired undefined error again
foo ;=> CompilerException ... Unable to resolve symbol: foo in this context
How can I test wether a variable has been declared or assigned (i.e. check if "a" is defined, when I expect a program to call some code like this (def a (create-a)) ?
And related --- how does the answer to this question relate to the problem of resolving a symbol (i.e. a function) which has been declared ? Clojure: determine if a function exists
It seems like a defined variable should be checkable in the same sense that a defined function is, but I'm finding that the solution for determining if a function exists is not sufficient for determining wether a variable exists.
Some context : I'm writing unit tests for a multideveloper project, and want to make sure that the test data, and the methods in different classes have been defined. Since there is no good IDE support for clojure, it seems to me that, given its loose structure, it is good to test method names and variable names existence before testing their outputs / content.
You can use resolve to see if the variable was bound/defined:
(resolve 'meaning)
nil
(def meaning 42)
#'user/meaning
(resolve 'meaning)
#'user/meaning
or you can boolean check it, if you need true/false:
(boolean (resolve 'meaning))
true
One way to do this is to use ns-resolve, for example:
user=> (def a "hello a")
user=> (ns-resolve *ns* 'a)
#'user/a
user=> (ns-resolve *ns* 'b)
;nil ; This assumes b hasn't been defined before...
Note that if you namespace-qualify the symbol to be checked then what you pass as first argument (*ns* in the example above) doesn't matter:
user=> (ns-resolve 'user 'a)
#'user/a
user=> (ns-resolve 'other 'a)
nil
user=> (ns-resolve 'other 'user/a)
#'user/a
The resolve function mentioned by #tolitius is actually a shorthand for ns-resolve where the namespace argument always evaluates to ns, depending on the use case it might be more handy.
As others have said, resolve will return the var for a symbol if there is one defined, or nil. Further, you can check if the var has a value bound to it by using bound?.
user=> (resolve 'foo)
nil
user=> (def foo)
#'user/foo
user=> (resolve 'foo)
#'user/foo
user=> (bound? #'foo)
false
user=> (def foo 5)
#'user/foo
user=> (bound? #'foo)
true
Since there is no good IDE support for clojure it seems to me that,
given its loose structure, it is good to test method names and
variable names existence before testing their outputs / content.
This is nuts. You really want a test to say "Oops! You forgot to define foobar!" instead of just trying to run foobar and seeing Clojure's "Unable to resolve symbol" message?
What do you gain from this? You lose the stacktrace, which could be useful if, for example, the test is passed the wrong function name by some other code. Much better to know what line mis-spelled foobar than to search through your whole test namespace.