While toying with Clojure I wrote a function, which relied on someSymbol being undefined at first run as (resolve someSymbol) would return nil. Turns out, that by defn-ing funcion with def somewhere in it causes the symbol to be defined:
(resolve 'someSymbol)
(defn resolvePokus []
(prn "I was evaluated")
(def someSymbol 1)
)
(resolve 'someSymbol)
in REPL yields:
nil
#'user/resolvePokus
#'user/someSymbol
Does that mean, that some special expressions are evaluated on running defn? Which ones?
Brief look into defn's source didn't reveal anything to me, except for there is one TODO comment in this core function :)
I assume you are running in the repl. I do not see the behavior you describe:
clj.core=> (resolve 'someSymbol)
nil
clj.core=> (defn resolvePokus []
#_=> (prn "I was evaluated")
#_=> (def someSymbol 1)
#_=> )
#'clj.core/resolvePokus
clj.core=> (resolve 'someSymbol)
#'clj.core/someSymbol
; try to use it -> error "Unbound..."
clj.core=> someSymbol
#object[clojure.lang.Var$Unbound 0x542f6481 "Unbound: #'clj.core/someSymbol"]
clj.core=> (resolvePokus) ; run the function
"I was evaluated"
#'clj.core/someSymbol
clj.core=> (resolve 'someSymbol) ; still can resolve
#'clj.core/someSymbol
clj.core=> someSymbol ; now we can use it
1
clj.core=> (declare xyz) ; creates a var, but unbound
#'clj.core/xyz
clj.core=> (resolve 'xyz) ; we can see resolve it
#'clj.core/xyz
clj.core=> xyz ; try to use it -> error "Unbound"
#object[clojure.lang.Var$Unbound 0x2d1d436f "Unbound: #'clj.core/xyz"]
clj.core=> (def xyz 5) ; define it
#'clj.core/xyz
clj.core=> (resolve 'xyz) ; still can resolve
#'clj.core/xyz
clj.core=> xyz ; now we can use it
5
So when I define the function, after typing the final parentheses the repl prints that #'clj.core/resolvePokus is defined but not someSymbol. The final resolve call still returns nil.
However, if you read further it seems that Clojure does the equivalent of a (declare someSymbol) when it first sees the (def someSymbol 1). You can see the same behavior when I manually (declare xyz) and later give it a value via (def xyz 5)
You may wish to look at this answer. The details involve the "hidden" var and how it is the anonymous intermediary between the symbol xyz and the value 5.
P.S. The above example was run on Ubuntu 16.04, Clojure 1.8, Java 1.8
Related
When I start a repl with lein repl I can run the function greet and it works as expected.
(ns var-test.core
(:gen-class))
(declare ^:dynamic x)
(defn greet []
(binding [x "Hello World."]
(println (load-string "x"))))
(defn -main [& args]
(greet))
But if run the code via lein run it fails with
java.lang.RuntimeException: Unable to resolve symbol: x in this context.
What am I missing?
Is the var x dropped during compilation, despite being declared, since it is never used outside of the string?
Edit:
Solution
#amalloy's comment helped me understand I need to bind *ns* in order load the string within the expected namespace, instead of a new, empty namespace.
This works as expected:
(ns var-test.core
(:gen-class))
(declare ^:dynamic x)
(defn greet []
(binding [x "Hello World."
*ns* (find-ns 'var-test.core)]
(println (load-string "x"))))
(defn -main [& args]
(greet))
Wow, I've never seen that function before!
According to the docs, load-string is meant to read & load forms one-at-a-time from an input string. Observe this code, made from my favorite template project:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require [tupelo.string :as str]))
(dotest
(def y "wilma")
(throws? (eval (quote y)))
(throws? (load-string "y"))
So it appears that load-string starts with a new, empty environment, then reads and evaluates forms one at a time in that new env. Since your x is not in that new environment, it can't be found and you get an error.
Try it another way:
(load-string
(str/quotes->double
"(def ^:dynamic x)
(binding [x 'fred']
(println :bb (load-string 'x'))) " ))
;=> :bb fred
In this case, we give all the code as text to load-string. It reads and eval's first the def, then the binding & nested load-string forms. Everything works as expected since the working environment contains the Var for x.
Some more code illustrates this:
(spy :cc
(load-string
"(def x 5)
x "))
with result
:cc => 5
So the eval produces the var x with value 5, then the reference to x causes the value 5 to be produced.
To my surprise, the partial load-string works in a fresh REPL:
demo.core=> (def x "fred")
#'demo.core/x
demo.core=> (load-string "x")
"fred"
So load-string must be coded to use any pre-existing
REPL environment as the base environment. When using lein run, there is no REPL environment available, so load-string starts with an empty environment.
Given the following function
(defn func []
(break!))
I want the break! function to start a repl, and inside that repl I can print the callstacks that invokes func.
The feature is like ipdb in Python, which comes quite handy when we want to interactively investigate inside the runtime of some function.
A very basic version could just be:
(defn break! [] (clojure.main/repl))
That will start a new, nested REPL, and when you exit it (with ^D -- or ^Z on Windows), it will continue on.
You can't evaluate locals, but if you write break! as a macro, you can at least display the active locals before starting the REPL:
user=> (defmacro break! []
(let [locals (into {} (map (juxt keyword identity)) (keys &env))]
(prn locals)
(clojure.main/repl :prompt #(print "nested> "))))
#'user/break!
user=> (defn foo "Using the break! function." [a b] (break!))
#'user/foo
user=> (foo 13 42)
{:a 13, :b 42}
nested> (doc foo)
-------------------------
user/foo
([a b])
Using the break! function.
nil
nested> ^D
nil
user=>
If you want the stacktrace as data inside the nested REPL, you can evaluate (:trace (Throwable->map (Throwable.)))
Here is an example from joy of clojure:
(let [x 9, y '(- x)]
(println `y)
(println ``y)
(println ``~y)
(println ``~~y))
Output from repl:
typedclj.macros/y
(quote typedclj.macros/y)
typedclj.macros/y
(- x)
If I rearrange the order of quote/unquote a bit, results are still the same (I am wondering why):
(let [x 9, y '(- x)]
(println `y)
(println ``y)
(println `~`y)
(println `~`~y))
But if I put the tilde in front:
(let [x 9, y '(- x)]
(println `y)
(println ``y)
(println `~`y)
(println ~``~y))
I get a strange error:
CompilerException java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure.core/unquote, compiling:(/Users/kaiyin/personal_config_bin_files/workspace/typedclj/src/typedclj/macros.clj:1:25)
Why do I get this error?
Short answer: you're trying to unquote outside of a syntax-quote, and that doesn't make sense.
More details:
This error is generated from the final println. Observe that
(println ~``~y)
expands to
(println (unquote (syntax-quote (syntax-quote (unquote y))))
This happens by the virtue of ~ and the backtick character being reader macros. The expansion unquote is not actually a normal function or a macro. It's a special form which is defined only inside of a syntax-quote. You can see this in the compiler source, in LispReader.java. When you use it outside of a syntax-quote form, the reader macro has still happened but there's no such function as 'unquote'. There is only a bare (def unquote) in core.clj (the very first definition).
When you do a def like that, you end up with a var whose initial binding is an instance of the class cloure.lang.Unbound (it's one of the constructors on clojure.lang.Var. This subclasses clojure.lang.AFn but doesn't specify any arities; so every invocation of it as a function calls throwarity, giving you this exception.
Given that this works as I'd expect:
(do
(println (resolve 'a)) ; nil
(def a "a")
(println (resolve 'a))) ; #'user/a
I'd like to understand why this doesn't:
(future
(println (resolve 'b)) ; #'user/b (shouldn't it be still undefined at this point?)
(def b "b")
(println (resolve 'b))) ; #'user/b
I'd also like to know if this is a proper solution (not exactly solving the same problem, but doing an equivalent job in my context):
(def c (atom nil))
(future
(println #c) ; nil
(reset! c "c")
(println #c)) ; c
This behaviour comes about as a result of the way in which def forms are compiled.
Note that using def forms not at top-level (or perhaps inside a top-level let -- see below for more comments on this case) is frowned upon as a matter of style in any case. The snippet using an Atom, on the other hand, is fine -- no reason not to use it if it does what you want.
On to the def story:
Compilation of def forms:
When a def form is encountered, a Var of the appropriate name is created at that moment by the compiler in the current namespace. (Attempting to def a Var outside the current namespace by using a namespace-qualified symbol as the name argument to def results in an exception). That Var is at first unbound and stays unbound until the def is actually executed; for a top-level def, that'll be right away, but for a def hidden inside a function's body (or inside a let form -- see below), that'll be when the function is called:
;;; in the user namespace:
(defn foo []
(def bar "asdf")
:done)
; => #'user/foo
bar
; => #<Unbound Unbound: #'user/bar>
;;; let's change the namespace and call foo:
(ns some.ns)
(user/foo)
; => :done
bar
; exception, the bar Var was created in the user namespace!
user/bar
; => "asdf"
; the Var's namespace is fixed at compile time
The first example -- with the do form:
Top level dos are treated as if their contents were spliced into the flow of code at the place where the do occurs. So if you type (do (println ...) (def ...) (println ...)) at the REPL, that's equivalent to typing in the first println expression, then the def, then the second println expression (except the REPL only produces one new prompt).
The second example -- with future:
(future ...) expands to something close to (future-call (fn [] ...)). If ... includes a def form, it'll be compiled in the manner we have seen above. By the time the anonymous function executes on its own thread the Var will have been created, thus resolve will be able to find it.
As a side note, let's have a look at a similar snippet and its output:
(let []
(println (resolve 'c))
(def c "c")
(println (resolve 'c)))
; #'user/c
; #'user/c
; => nil
The reason is as before with the extra point that let is first compiled, then executed as a whole. This is something one should keep in mind when using top-level let forms with definitions inside -- it's generally ok as long as no side-effecty code is intermingled with the definitions; otherwise one has to be extra careful.
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)