I'm studing macros and as project example building an route system. An route (functions get/post/put/...) can be attached to an scope, when it occurs the route url is prefixed by the actual scope, example:
;; base scope macro
(defmacro scope [url & body]
`(let [~'base-scope ~url
~'get #(str ~'base-scope %)]
~#body))
(scope "admin/"
(get "stackoverflow")) ;; OK! returns 'admin/stackoverflow'
The problem is that scope can be nested:
(scope "admin/"
(scope "api/"
(get "stackoverflow")))
My question is: How can I make a lookup under the actual scope, searching for route prefixes(scopes)? I know that I have access to &env and &form implicits; should I use &env and try to create a kind of hidden prefixes, or use &form?
One option would be to use dynamic bindings – have a Var initially bound to [] and conj scopes on to it in scope-emitted binding forms. Overall it should be pretty straightforward, and also limited in some ways – you'd have to be careful about the dynamic extent / lifetime of your bindings.
If you're after something lexically scoped, you could use tools.macro's local macros to redefine scope invocations nested within other scope invocations. (In that case I would factor out as much of the actual logic into a helper function or two.)
As a very straightforward alternative, you could introduce a distinguished local name – preferably generated using gensym – and use it in scope's expansion much like the dynamic binding of the distinguished Var in the approach described above. The difference is that here the scopes would actually be lexically scoped. There's at least one caveat in that evil user code in the body could access or shadow the distinguished local – it's pretty unlikely with a gensym, though not that difficult if one feels like breaking things. The key point, though, is that one might be justified in feeling uncomfortable about "globally magic locals".
Finally, you could also introduce fresh "locally magic locals" in each expansion and search for them in &env. Here's a simple proof of concept using metadata to mark the magic locals:
(defmacro scope [sname & body]
(let [scopes (filterv #(contains? (meta %) :scope) (keys &env))
maybe-printout (if (seq scopes)
[(list* `println scopes)])]
`(let [~(with-meta (gensym "scope__") {:scope true}) '~sname]
~#maybe-printout
~#body)))
At the REPL,
(scope :foo
(scope :bar
(scope :quux
(scope :xyz))))
prints out
:foo
:foo :bar
:foo :bar :quux
returning nil.
(set! *print-meta* true) and a macroexpand call reveal that the above expands to
(let* [^{:scope true} scope__16668 (quote :foo)]
^{:line 4, :column 6}
(scope :bar
^{:line 5, :column 8}
(scope :quux
^{:line 6, :column 10}
(scope :xyz))))
Of course only the :scope metadata is interesting. If it's ok to assume that scope names must be compile-time constants, it's even possible to retrieve their actual values at compile time (see clojure.lang.Compiler$LocalBinding and clojure.lang.Compiler$ConstantExpr), but that'd be an unnecessary hack in this case.
This doesn't solve the whole problem as written – rather than creating new individual "scope locals", scope should probably maintain locals with growing vectors of scope names to preserve ordering. This can be done e.g. by searching for a :scope-tagged local and shadowing it if it exists (if not, we're in a top-level scope and a new local should be created).
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
I was reading Clojure in Action chapter 8 about TDD and experimented with the stubbing macro. It uses the dynamic binding mechanism to stub functions. Alas, in Clojure 1.3 it is not possible to use the binding mechanism for non-dynamic vars, so the stubbing macro doesn't work in most cases, unless you explicitly declare the var which points to a function dynamic. Then I wondered how stubbing is done in Midje and tried to find the source for 'provided', but I couldn't find it. So here it goes:
How is 'provided' implemented in a fact in Midje? Can someone explain this in detail?
Clojure 1.3 provides a with-redefs macro that works even with vars that haven't been declared dynamic:
user=> (def this-is-not-dynamic)
user=> (with-redefs [this-is-not-dynamic 900] this-is-not-dynamic)
900
For backward compatibility, Midje uses its own version, whose guts look like this:
(defn alter-one-root [[variable new-value]]
(if (bound? variable)
(let [old-value (deref variable)]
(alter-var-root variable (fn [current-value] new-value))
[variable old-value])
(do
(.bindRoot variable new-value)
[variable unbound-marker])))
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.
On a particular namespace I am working on I am beginning to run out of function names. Is there a way to get a warning like the one I get if I override a symbol from another namespace if I reuse a symbol which is already bound to a function in the same namespace?
If this is enough of a problem that you'd be willing to replace a (set of) core macro(s), you could try this approach:
(ns huge.core
(:refer-clojure :exclude [defn]))
(defmacro defn [name & defn-tail]
(assert (nil? (resolve name))
(str "Attempting to redefine already defined Var "
"#'" (.name *ns*) "/" name))
`(clojure.core/defn ~name ~#defn-tail))
Then any attempt to redefine an existing Var with defn will fail:
user=> (defn foo [] :foo)
#'user/foo
user=> (defn foo [] :bar)
AssertionError Assert failed: Attempting to redefine already defined Var #'user/foo
(nil? (resolve name)) user/defn (NO_SOURCE_FILE:2)
You could similarly replace defmacro; in that case you would have to call clojure.core/defmacro when defining your own variant.
Plain, unadorned def is a special form and receives magic treatment from the compiler, so you could still overwrite existing Vars with it. If you would like to guard against name clashes on that flank too, you could switch to something like defvar (used to be available in clojure.contrib.def) with a similar custom assert.
This isn't quite an answer to your question but may help avoid the issue depending on how the functions in your namespace are being used. You could make them into local functions using letfn, allowing you to reuse names for functions that are only used within the context of another function.
(defn main-fn [x]
(letfn [(secondary-fn [x] (* x x))
(another-fn [x] (secondary-fn (inc x)))]
(/ (another-fn x) 4)))
Even if you restrict yourself to single-character function names, you are in no danger of running out, as there are (about) 64 thousand Unicode characters, any one of which is a valid function name.
Given that you can in fact have names that are ten thousand characters long, you are on even safer ground.