Why is next not gensymed? - clojure

Here x is gensymned because some expression passed to and can have x in it and to avoid that conflict. Then why is next not gensymed? Couldn't next lead to variable capture?
(defmacro and
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~#next) and#))))

x is not gensymmed, and shouldn't be. The gensymmed thing here is and#, which is gensymmed for the usual reason: it is a synthetic binding introduced into the caller's scope for the macro's internal-only usage. x and next are none of these things: they are not introduced as bindings, nor are they for the macro's internal-only usage. They are code snippets (a form and a seq of forms) supplied by the caller, intended to be present in the expanded body for the caller's purposes.

Related

Clojure Macros: Accumulate value over scope

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

Practical Clojure: macros and Java interop

In Practical Clojure's chapter on Java interop, the authors note the following about the Java interop "syntactic sugar" (e.g. (.method object arguments) instead of (. object method arguments)):
Since these “syntactic sugar” expansions happen in the same compilation phase as macro-expansion, macros that do complex code-generation may need to avoid them and use the new and . (dot) special forms directly.
I don't understand why "syntactic sugar" expansion happening in the same phase as macro expansion is a problem. Is it because there may be issues with the order of expansions?
Macros concerned with generating interop calls typically should use the desugared special form, but that's not because of when desugaring happens, nor is it a problem. And they don't have to: more times than I care to count, I've seen someone write:
(defmacro call [obj method & args]
`(~(symbol (str "." (name method))) ~obj ~#args))
which is just a total mess, compared to how it would look with the appropriate tool:
(defmacro call [obj method & args]
`(. ~obj ~method ~#args))

What does ^:dynamic do in Clojure?

I've googled for "clojure dynamic" and "clojure dynamic scope" and read over 10 articles and I still don't have a clear understanding of what ^:dyanmic does. I think this article may be answering my question, but the code samples seem to be "missing" so I'm not even sure if it's referring to the same thing I'm confused about.
I'm trying to fix an issue in the clj-http project but first I have to understand the code. It has functions defined like this:
(defn ^:dynamic parse-html
"Resolve and apply crouton's HTML parsing."
[& args]
{:pre [crouton-enabled?]}
(apply (ns-resolve (symbol "crouton.html") (symbol "parse")) args))
But I don't understand what that ^:dynamic means/does. Can anyone explain it to me in a really simple way?
It is defining the function as being dynamically scoped.
In other words, this allows someone to re-bind parse-html in a given function invocation and have that new binding apply only to functions called from that specific invocation.
If parse-html were not dynamically scoped then re-binding it would cause the new binding to be seen by any code that uses parse-html and not just code that was activated by the function invocation that did the re-binding.
Dynamic scoping is useful as a substitute for globally scoped variables. A function can say "let current_numeric_base = 16; call other functions;" and the other functions will all print in hexadecimal. Then when they return, and the base-setting function returns, the base will return to whatever it was.
http://c2.com/cgi/wiki?DynamicScoping
As was pointed out in the comments below, you can't actually re-bind variables that aren't dynamically scoped in Clojure. If you could, updating a variable that is lexically scoped will impact all code that is executed even if it is running in a different call stack from where the re-bind occurred.
So maybe some pseudo-code will make the difference between dynamic and lexical scope clear.
Example of using a dynamically scoped variable:
(def ^:dynamic a 0)
(defn some-func [x] (+ x 1))
; re-binds a to 1 for everything in the callstack from the (binding)
; call and down
(binding [a 1]
(print (some-func a)))
; a was only re-bound for anything that was called from
; within binding (above) so at this point a is bound to 0.
(print (some-func a))
would print:
2
1
Example of a lexically scoped variable:
(def a 0)
(defn some-func [x] (+ x 1))
; re-binds a to 1 for everyone, not just things that
; are in the callstack created at this line
(set-var [a 1] ; set-var is a made up function that can re-bind lexically scoped variables
(print (some-func a)))
; a was lexically scoped so changing it changed
; it globally and not just for the callstack that
; contained the set-var.
(print (some-func a))
would print:
2
2

In clojure how can defmacro be defined in terms of itself?

I have been looking at the source for defmacro which uses "let" in its definition:
(def
^{:doc "Like defn, but the resulting function name is declared as a
macro and will be used as a macro by the compiler when it is
called."
:arglists '([name doc-string? attr-map? [params*] body]
[name doc-string? attr-map? ([params*] body)+ attr-map?])
:added "1.0"}
defmacro (fn [&form &env
name & args]
(let [prefix (loop [p (list name) args args]
However, "let" is defined as a macro itself:
(defmacro let
"binding => binding-form init-expr
Evaluates the exprs in a lexical context in which the symbols in
the binding-forms are bound to their respective init-exprs or parts
therein."
{:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]}
[bindings & body]
(assert-args
(vector? bindings) "a vector for its binding"
(even? (count bindings)) "an even number of forms in binding vector")
`(let* ~(destructure bindings) ~#body))
Can someone explain how this works as I can't understand how "defmacro" can be defined in terms of things which need "defmacro" to already be defined. (if that makes sense :)
This is possible because before defining defmacro function in core.clj there is already a definition of let at this location (which gets redefined later). Macros are just normal functions and the var they are bound to has meta data key :macro with value true so that at compile time the compiler can differentiate between a macro (which execute at compile time) with a function, without this meta key there is no way to differentiate between a macro and a function because macro itself is a function that happens to process S-expressions.
recusrive macros work fine and occur in many place in both the clojure language core and in other programs. macros are just functions that return S-Expressions, so they can be recursive just as functions can. In the case of let in your example it's actually caling let* which is a different function (its fine to have * in a functions name), so although recursive macros are fine, this doesn't happen to be an example of them

Avoid overriding variable names

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.