Is ^:dynamic an atomic keyword, or a combination? - clojure

The function of ^:dynamic is clear (see, for instance, clojure and ^:dynamic). My question: Is ^:dynamic an atomic i.e. indivisible keyword? If not, are any of the below also valid? What do the operators/decorations ^ and : add to the expression?
(def ^:dynamic y 5) -- Valid (known).
(def dynamic y 5) -- but the rest of these? ...
(def ^dynamic y 5)
(def :dynamic y 5)
(def ^: y 5)
Alternatively, and maybe there's no clear answer: If ^:dynamic is an indivisible keyword, why attach all the funny punctuation to it?

This declaration
(def ^:dynamic x 5)
is equivalent to
(def ^{:dynamic true} x 5)
In general ^ followed by a keyword or map is a metadata reader macro. Where followed by a keyword, it sets that keyword to true in the object's metadata map.
To summarize: ^:dynamic is not an "indivisible" keyword; it's a metadata reader macro followed by an ordinary keyword (:dynamic in this case).

Related

How to write an Clojure macro to get var's value?

user=> (def v-1 "this is v1")
user=> (def v-2 "this is v2")
user=> (defmacro m [v] (symbol (str "v-" v)))
user=> (m 1)
"this is v1"
user=> (m 2)
"this is v2"
user=> (let [i 2] (m i))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: v-i in this context, compiling:(NO_SOURCE_PATH:73:12)
Can I write a macro let both
(m 2)
and
(let [i 2] (m i))
get "this is v2" ?
This is possible without a macro:
(defn m [v] (var-get (resolve (symbol (str "v-" v)))))
(m 1) ;; => "This is v1"
(let [i 2] (m i)) ;; => "This is v2"
You can use a macro too if you want:
(defmacro m [v] `#(resolve (symbol (str "v-" ~v))))
A plain function seems much more likely to be what you want.
First, though, to address the original question, if you wanted to insist on using a macro, macros are regular functions that happen to be called at compile time, so you can look up a Var using its symbolic name and obtain its value using deref just like you could at (your application's, as opposed to your macro's) runtime:
(defmacro var-value [vsym] #(resolve vsym))
(def foo 1)
(var-value foo)
;= 1
(macroexpand-1 '(var-value foo))
;= 1
Note that the above 1 is the actual macroexpansion here. This is different to
(defmacro var-value [vsym] `#(resolve ~vsym))
in that the latter expands to a call to resolve, and so the lookup given that implementation is postponed to your app's runtime.
(macroexpand-1 '(var-value foo))
;= (clojure.core/deref (clojure.core/resolve foo))
So this code will just be inlined wherever you call the macro.
Of course the macro could also expand to a symbol – e.g.
(defmacro prefixed-var [suffix]
`(symbol (str "v-" ssuffix)))
will produce expansions like v-1 (for (prefixed-var 1)) etc.
Going back to the subject of the suitability of macros here, however, if you use a macro, all the information that you need to produce your expansion must be available at compile time, and so in general you cannot use the values of let / loop locals or function arguments in your expansion for the fundamental reason that they don't have any fixed value at compile time.1
Thus the cleanest approach would probably be to wrap a resolve call in defn and call the resulting function – although of course to know for sure, we'd need to know what problem you were trying to solve by introducing a macro that performs a Var lookup.
1 Except if statically assigned constant values, as in the example given in the question text; I'm assuming you're thinking of using runtime values of locals in general, not just those that whose initialization expressions are constant literals.

what is ^ in Clojure when define a function?

I'm new to Clojure and I've been messed up with ^ in Clojure
I'm currently reading clojure code of Jepsen which is used to test the consistency of distributed database.
You can find the code here.
In row 50 there is a ^MongoDatabase. Or:
(defn ^MongoCollection collection
"Gets a Mongo collection from a DB."
[^MongoDatabase db collection-name]
(.getCollection db collection-name))
I have no idea what it is because ^MongoDatabase or MongoCollection is never used in this function.
Can anyone give me some help. Thanks a lot.
In this context, that's a type hint saying collection should return a MongoCollection instance and db arg should be a MongoDatabase instance. This is useful for performance reasons, to avoid unnecessary reflection.
See this guide for more.
Another use of ^ is for type hints. These are used to tell the compiler what type the value will be and allow it to perform type specific optimizations thus potentially making resultant code faster:
The cap symbol ^ is used in Clojure for two purposes.
The first one is for type hints. When declaring a function, you may mark arguments' types or the result value as follows:
(defn ^String concat-strings
[^String a ^String b]
(str a b))
Type hints help the compiler to perform some optimizations.
The second option of using cap is when declaring metadata. The metadata might be either a boolean flag or a map. For example:
(def ^:private secret "test")
Now the variable above is marked as private so it won't be available from other namespaces.
Here is a meta-map usage example:
(def ^{:private true
:doc "My super secret password"
:added "product-version"}
secret
"test")
Let's try to read the metadata for that variable:
(meta #'secret)
returns
{:private true,
:doc "My super secret password",
:added "product-version",
:line 70,
:column 7,
:file "*cider-repl localhost*",
:name secret,
:ns #namespace[user]}
Another point to beware of is that type hints can be deceptive (i.e. they have no "enforcement" or "warning" utility):
(defn foo [x]
(type x))
(defn bar [^String x]
(type x))
(foo "abc") => java.lang.String
(foo 123) => java.lang.Long
(bar "abc") => java.lang.String
(bar 123) => java.lang.Long
In general, I would avoid type hints as they are rarely necessary (unless dealing with low-level Java code).

Idiomatic `and` & `or` functions (not macros) in Clojure

Strange as it may sound, I am looking for function versions of the and and or macros in Clojure.
Why? For one I am curious.
Second, I want to use or in precondition and postcondition checks. This does not work:
(defn victor
[x]
{:post (or (nil? %) (vector %))}
;; ...
)
I want the postcondition to check to see if victor returns a vector or nil, but it fails:
#<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/or, compiling:(test/test.clj:10:1)>
I don't think bit-and and bit-or are quite what I'm looking for.
Update: This syntax works without an error:
(defn victor
[x]
{:post [(or (nil? %) (vector %))]}
;; ...
)
I'm still curious if functions exist, though.
I think the standard method is simply to wrap and and or in functions, e.g. (fn [x y] (or x y)). In some contexts, another function will work. For example, a note in the clojure docs for and suggests using (every? identity [true false]). some, not-every?, and not-any? can be used in a similar way.
In general, and and or functions would be undesirable because they cannot use short-circuiting. Consider the following code:
(and false some-expensive-fn)
(or true some-expensive-fn)
With and and or as macros the above code won't execute some-expensive-fn, because it is unnecessary to determine the overall truth value of the expression. In function expressions the arguments are evaluated before being passed to the function, but in macros they are not.
#Triangle Man is right. Short-circuiting won't work, but nevertheless you can define your own function versions:
user=> (defn && [x y] (and x y))
#'user/&&
user=> (&& true false)
false
user=> (&& true true)
true
user=> (defn || [x y] (or x y))
#'user/||
user=> (|| true false)
true
user=> (|| true true)
true
user=> (|| false false)
false
user=>

How can I evaluate "symbol" and "(symbol 1)" with the same name?

I want to get following results when I evaluate edit-url and (edit-url 1).
edit-url --> "/articles/:id/edit"
(edit-url 1) --> "/articles/1/edit"
Is it possible to define such a Var or something?
Now, I use following function, but I don't want to write (edit-url) to get const string.
(defn edit-url
([] "/articles/:id/edit")
([id] (str "/articles/" id "/edit")))
Thanks in advance.
If those behaviors are exactly what you want, print-method and tagged literals may be used to imitate them.
(defrecord Path [path]
clojure.lang.IFn
(invoke [this n]
(clojure.string/replace path ":id" (str n))))
(defmethod print-method Path [o ^java.io.Writer w]
(.write w (str "#path\"" (:path o) "\"")))
(set! *data-readers* (assoc *data-readers* 'path ->Path))
(comment
user=> (def p #path"/articles/:id/edit")
#'user/p
user=> p
#path"/articles/:id/edit"
user=> (p 1)
"/articles/1/edit"
user=>
)
edit-url will either have the value of an immutable string or function. Not both.
The problem will fade when you write a function with better abstraction that takes a string and a map of keywords to replace with words. It should work like this
(generate-url "/articles/:id/edit" {:id 1})
Clojure is a "Lisp 1" which means that is has a single namespace for all symbols, including both data scalars and functions. What you have written shows the functionally of both a string and a function but for a single name, which you can do in Common Lisp but not Clojure (not that a "Lisp 2" has its own inconveniences as well).
In general this type of "problem" is a non issue if you organize your vars better. Why not just make edit-url a function with variable arity? Without arguments it returns something, with arguments it returns something else. Really the possibilities are endless, even more so when you consider making a macro instead of a function (not that I'm advocating that).

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