Clojure global variable behavior in a threaded environment - clojure

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.

Related

Clojure optional definitions

In Python I'm able to do something like:
fast_thing_available = True
try:
import fast_thing
except ImportError:
fast_thing_available = False
# snip
if fast_thing_available:
default = fast_thing
else:
default = slow_thing
Is it possible to do the same thing in Clojure?
I've tried next, but it fails (e.g. import is still required):
(ns sample.ns)
(def ^:private long-adder-available (atom false))
(try
(do
(import 'java.util.concurrent.atomic.LongAdder)
(swap! long-adder-available (constantly true)))
(catch ClassNotFoundException e ()))
(when (true? #long-adder-available)
(do
; Here I'm using LongAdder itself
))
Code throws IllegalArgumentException: unable to resolve classname: LongAdder even if LongAdder itself is not available.
As pointed out by #amalloy in the comments, the code inside when does not compile. I am not sure if there is a way to re-write that code so it compiles. However it is possible to avoid compiling it altogether. Clojure macros can be used to exclude code from compilation.
A macro can attempt importing a class and only if that succeeds emit the the code using the class. There are simpler ways to check if a class exists in the classpath, but it is important to call import at compile time. That way the code can use simple class names (like LongAdder).
When applied to this problem, the solution might look like the sample below. The piece of code calling import is a bit ugly with eval etc. but it is tough to pass non-literal arguments to import. If there is no need for this code to be generic, the class name can be hard-coded and a few other things can be simplified.
(ns sample.core)
(defmacro defn-if-class
"If clazz is successfully imported, emits (defn name args then)
Emits (defn name args else) otherwise."
[clazz name args then else]
(if (try (eval `(import ~clazz)) true (catch Exception e nil))
`(defn ~name ~args ~then)
`(defn ~name ~args ~else)))
(defn-if-class java.util.concurrent.atomic.LongAdder
foo []
;; if class exists
(doto (LongAdder.)
(. increment)
(. sum))
;; else
"fallback logic in case the class is not in classpath")
(defn -main [& args]
(println (foo)))
I should mention that the answer is heavily inspired by Jay Fields' blog post "Clojure: Conditionally Importing" and this answer.

Curious behavior of when-not and/or defmulti

Why does it happen that after I execute defmulti within a when-not, the previously unresolved symbol resolves fine, but not bound to the value?
user=> (resolve 'buux)
nil
user=> (when-not (resolve 'buux) (defmulti buux class))
nil
user=> (resolve 'buux)
#'user/buux
user=> (bound? #'buux)
false
user=> (defmulti buux class)
#'user/buux
user=> (bound? #'buux)
true
defmulti will be expanded with a let-block that uses def to define the symbol. As a matter of fact, the expression returned by defmulti will not be evaluated, but it will be generated as form using let, Thus, the object becomes defined globally. This results in your test-condition (for when not) to succeed after the var has been defined, before the multi-fn was created and the root binding of the var was affected. Your defmulti block was never executed (also the when-not expression returned nil), but expanded.
Further explanation:
Here you can see how that happens:
(macroexpand '(defmulti buxx class))
Now you can see the form that the macro call will generate:
(clojure.pprint/write (macroexpand '(defmulti buxx class))
:with-dispatch clojure.pprint/code-dispatch)
=>
(let*
[v__4080__auto__ (def buxx)]
(clojure.core/when-not
(clojure.core/and
(.hasRoot v__4080__auto__)
(clojure.core/instance? clojure.lang.MultiFn #v__4080__auto__))
...
This results in (def buux) being expanded. If you evaluate (def buux) in your repl you can make the same tests.
From the docstring of def:
def yields the var itself (not its value).
This means, when being expanded, it is being replaced with a (possibly unbound) var.
So when being expanded, def always creates a var but the optional form that returns the new value (for the var) will be only evaluated when the expanded def is evaluated. Macros and special forms will be expanded before they are actually evaluated. E. g. testing with
(defmacro i-have-side-effects
[]
(println "I was invoked!")
42)
(when-not true
(println (i-have-side-effects)))
=>
#'user/i-have-side-effects
I was invoked!
nil
So probably you should not define a multi-method conditionally anyway.

How can I define a variable in another namespace within a function/macro in Clojure?

I'm experimenting with ns in Clojure, here's what I try:
user=> (in-ns 'some-ns)
#<Namespace some-ns>
some-ns=> (def aa 100)
#'some-ns/aa
some-ns=> (in-ns 'user)
#<Namespace user>
user=> (= some-ns/aa 100)
true
user=> (= user/aa 100)
CompilerException java.lang.RuntimeException: No such var: user/aa, compiling:(NO_SOURCE_PATH:5:1) ;this works as expected
user=> (defn function [] (in-ns 'some-other-ns) (def cc 100) (in-ns 'user))
#'user/function
user=> (function)
#<Namespace user>
user=> (= some-other-ns/cc 100)
CompilerException java.lang.RuntimeException: No such var: some-other-ns/cc, compiling:(NO_SOURCE_PATH:8:1)
user=> (= user/cc 100)
true
I'm confused, why it doesn't work in function? Also, I tried following:
user=> (binding [*ns* (create-ns 'some-a-ns)] (def dd 100))
#'user/dd
user=> (= some-a-ns/dd 100)
CompilerException java.lang.RuntimeException: No such var: some-a-ns/dd, compiling:(NO_SOURCE_PATH:11:1)
user=> (= user/dd 100)
true
according to clojure doc
Creates and interns or locates a global var with the name of symbol and a namespace of the value of the current namespace (*ns*).
what I'm missing?
PS. I know I can use (intern 'some-ns 'a 100), but what I really want is a generic function/macro to do like
(with-ns 'some-ns (def a 100))
(= some/a 100)
intern is the correct solution and you can use it in any functions / macros of your own. (Functions can call intern; macros can expand to code calling intern.)
def should only ever be used directly at top level or nested within top-level forms where it will be immediately executed as soon as the top-level form is. So, def in let is fine, def inside a function is not.
def receives special handling from the compiler in that the Vars defined by def forms are actual created as soon as the def is compiled; the initial bindings specified in def forms are installed, however, if and when the flow of control actually reaches the def form. This explains why the binding example doesn't work -- it is the compile-time value of *ns* which counts, while the binding introduced by this binding form will come into effect at run time.
Finally, if you absolutely insist on using def forms to create Vars at runtime, the way to do it is with eval:
(binding [*ns* some-ns]
(eval '(def foo 1)))
;; some-ns/foo comes into existence with a root binding of 1
Note that here def does occur at top-level and will be immediately executed after compilation.

Why does dotrace throw a StackOverflowError here?

(use '[clojure.contrib.trace])
(dotrace [str] (reduce str [\a \b]))
In a nutshell:
That's because trace-fn-call, which is the thing dotrace uses to wrap the functions to be traced, uses str to produce the nice TRACE foo => val output.
Extended explanation:
The dotrace macro does its magic by installing a thread binding for each Var holding a function to be traced; in this case, there is one such Var, clojure.core/str. The replacement looks roughly like so:
(let [f ##'str]
(fn [& args]
(trace-fn-call 'str f args)))
The trace-fn-call, to quote its docstring, "Traces a single call to a function f with args.". In doing so, it calls the traced function, takes note of the return value, prints out a nice informative message of the form TRACE foo => val and returns the value obtained from the traced function so that regular execution may continue.
As mentioned above, this TRACE foo => val message is produced used str; however, in the case at hand, this is actually the function being traced, so a call to it leads to another call to trace-fn-call, which makes its own attempt to produce the tracing output string using str, which leads to another call to trace-fn-call... ultimately leading to the stack blowing up.
A workaround:
The following modified versions of dotrace and trace-fn-call should work fine even in the presence of weird bindings for core Vars (note that futures may not be scheduled promptly; if that's a problem, see below):
(defn my-trace-fn-call
"Traces a single call to a function f with args. 'name' is the
symbol name of the function."
[name f args]
(let [id (gensym "t")]
#(future (tracer id (str (trace-indent) (pr-str (cons name args)))))
(let [value (binding [*trace-depth* (inc *trace-depth*)]
(apply f args))]
#(future (tracer id (str (trace-indent) "=> " (pr-str value))))
value)))
(defmacro my-dotrace
"Given a sequence of function identifiers, evaluate the body
expressions in an environment in which the identifiers are bound to
the traced functions. Does not work on inlined functions,
such as clojure.core/+"
[fnames & exprs]
`(binding [~#(interleave fnames
(for [fname fnames]
`(let [f# #(var ~fname)]
(fn [& args#]
(my-trace-fn-call '~fname f# args#)))))]
~#exprs))
(Rebinding trace-fn-call around a regular dotrace apparently doesn't work; my guess is that's because of clojure.* Var calls still being hard-wired by the compiler, but that's a separate matter. The above will work, anyway.)
An alternative would be to use the above my-dotrace macro together with a my-trace-fn-call function not using futures, but modified to call custom replacements for the clojure.contrib.trace functions using the following in place of str:
(defn my-str [& args] (apply (.getRoot #'clojure.core/str) args))
The replacements are straightforward and tedious and I omit them from the answer.

In Clojure, how to define a variable named by a string?

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.)