According to spec, def should intern the var in the current ns (i.e. *ns*). However, the following code does not look anything like it:
(ns namespace-b)
(defn def_something []
(ns namespace-a)
(println *ns*) ;prints namespace-a as it should
(def something 1)
)
(def_something)
(println namespace-b/something) ; prints 1
(println namespace-a/something) ; throws
What am I missing?
Notes:
defn is used just for clarity. Defining and running anonymous function works just as well.
I know that using def inside function is probably not very idiomatic. However, this is just extracted essence of a bigger problem I ran into.
The parser already interns the var to the current namespace at compile time, although it won't be bound immediately:
(defn dd [] (def x 0))
x ;; => #<Unbound Unbound: #'user/x>
The relevant piece of code can be found here, with the second parameter to lookupVar triggering the aforementioned interning for non-existing vars here.
The parses then generates an expression that references the previously created var, so the expression logic never leaves the current namespace.
TL;DR: def is something that the compiler handles in a special kind of way.
The key thing to understand about def is that it is a macro. This means that it does not resolve the namespace or create the binding at runtime, but beforehand, while the code is being compiled.
If you call a function that calls def, that call to def was already resolved to use the namespace in which the function was defined. Similarly, if you call functions inside a function body, the functions to call are resolved at compile time within the namespace where that function was defined.
If you want to generally bind values to namespaces at runtime, you should use the function intern, which lets you explicitly set the namespace to mutate.
All this said, namespace mutation is just that, it's procedural and is not thread safe and does not have nice declarative semantics like other options Clojure makes available. I would strongly suggest finding a way to express your solution that does not involve unsafe runtime mutation.
Related
Given the following in one file:
(ns demo.first)
(defmacro ^:private private-macro [a] a)
And the following in another file:
(ns demo.second
(:require [demo.first :as first]))
(first/private-macro 10)
The call to the private macro in demo.second will throw: var: #'demo.first/private-macro is not public, as I expect.
Now, is there a way to have this call succeed, without making the macro public?
For functions, I can do:
(#'first/private-macro 10)
But with a macro, it throws: Wrong number of args (1) passed to: first/private-macro.
I'm looking to unit test this private macro, and personally prefer using private meta over an impl namespace. Which is why I'm hoping there's a solution to this.
Thank You.
UPDATE:
I found out that since defmacro is itself a macro, it first expands into a form which creates the symbol and Var for the macro and add its metadata to it.
Thus:
(defmacro ^:private private-macro [a] a)
First is processed by the defmacro macro, and expanded into:
(do
(clojure.core/defn ^{:private true} private-macro
([&form &env a] a))
(. (var ^{:private true} private-macro)
^{:line 487, :column 49}
(setMacro))
(var ^{:private true} private-macro))
As you can see, what then happens is that:
A private-macro fn is declared with defn, and set to private.
This function takes 3 arguments [&form &env a]. This is why we get the wrong number of argument (1) exception when using #' to call the macro.
The private-macro var is set as a macro by calling its setMacro method.
The private-macro var is returned.
In essence, what is happening is that if you call the function pointed to by the private-macro var, such as is the case when using the (#'private-macro) syntax, you're actually calling the function you see above, which takes 3 arguments. If your macro itself took more than one argument, that function would take 2 + the number of args of your macro.
So I still don't know how to call a private macro:
At first I thought stubbing out &form and &env with nils would work:
(#'first/private-macro nil nil 10)
And for my simple macro above it does, and return 10. But on more complicated macros, which need to be expanded further, it doesn't, and instead I get the macro-expansion returned to me ?!?
Then I thought I could use alter-meta! to remove the private meta from the macro temporarily before calling it. As such:
(alter-meta! #'first/private-macro
(fn [meta] (dissoc meta :private)))
(first/private-macro 10)
(alter-meta! #'first/private-macro
(fn [meta] (assoc meta :private true)))
But this only works at the REPL. Try to compile your code afterwards, and it seems the Compiler itself will throw the var: #'demo.first/private-macro is not public error, even before the alter-meta! has a chance to run, thus failing compilation.
I don't really know why #' doesn't work the same as a normal call to the macro, and why passing nil to the &form and &env doesn't work for all macros. And how to make alter-meta! work at compile time. So if someone does know, please answer away!
And for my simple macro above it does, and return 10. But on more complicated macros, which need to be expanded further, it doesn't, and instead I get the macro-expansion returned to me ?!?
Yes. As you discovered, when you write (defmacro m [x] (list x x)), you:
Define a function m that consumes forms as input and produces forms as output
Tell the compiler to look for calls like (m a) and replace them with the result of calling your m function at compile time
By calling #'m instead, you bypass step 2: there is no call to the macro m, and so the compiler does not call it at compile time or replace the calling code with the result. Since #'m is just a regular function which takes code as input and produces code, when you bypass the special compiler behavior and call it at runtime, you of course get code as a result (which you can't do much with because it's runtime already).
Good news, though: there's rarely a compelling reason to make a macro private anyway, since it can do no harm to let other namespace call it. All the private macro does is expand into code the client could have written by hand anyway. So, if you control this macro, you should probably just make it public. If you don't, then you can just write whatever code the macro would have written for you.
If you absolutely insist on calling someone else's private macro, then you can split the parts (1) and (2) up, in a way: define your own macro whose implementation delegates to the function backing the private var in the other namespace:
(defmacro cheat [& args]
(apply #'m &form &env args))
Because cheat is your own macro, you can call it in the usual way, engaging the compiler's "call this at compile time" mechanism. Then you delegate to the function that generates the code you want, passing &form and &env explicitly.
Here's snippet:
(defmacro produce-constantly-fn []
(constantly :value))
(defmacro produce-fn []
(fn [& args] :value))
(defn test-fn []
((produce-fn)))
;; during evaluation of form below it throws:
;; java.lang.IllegalArgumentException
;; No matching ctor found for class clojure.core$constantly$fn__4614
(defn test-constantly-fn []
((produce-constantly-fn)))
Why last function cannot be compiled? The snippet can be considered as some sort macros abuse, but anyway...
I assume you defined your macro body without quoting and you are curious why it results in such a weird error message. If you really meant to define a macro for calling (constantly :value) then you should use quoting and it will work:
(defmacro produce-constantly-fn []
`(constantly :value))
(defn test-constantly-fn []
((produce-constantly-fn)))
=> #'user/test-constantly-fn
(test-constantly-fn)
=> :value
Now going back to your case without quoting. It looks really interesting and mysterious so I did some digging. These are my findings:
When you define a macro:
(defmacro produce-constantly-fn []
(constantly :value))
it will just create a function named produce-constantly-fn and mark it as a macro (it's still a Clojure function).
When you look into the implementation of constantly you will find (docs and meta omitted):
(defn constantly [x]
(fn [& args] x))
Under the hood it will compile to a closure object which will implement IFn and will have a single constructor parameter to close over x parameter. Something like this in Java code:
public class clojure.core$constantly$fn__4614 {
private final Object x;
public clojure.core$constantly$fn__4614(Object x) {
this.x = x;
}
public Object invoke(...) {
return x;
}
// other invoke arities
}
Now when you have following sexp:
(defn test-constantly-fn []
((produce-constantly-fn)))
I noticed that Clojure reader evals (produce-constantly-fn) which should return just a function object (produced by calling (constantly :value)) but I found in debugger that it produces clojure.core$constantly$fn__4614. symbol instead (notice the . at the end of the symbol - it is a Java interop form for calling a constructor). It looks like a function object/value gets somehow converted to a symbol representing its constructor call. I could find that the function value gets converted into Compiler$InvokeExpr object containing references to the compiled class name which is probably somehow converted into the symbol.
The reader tries to resolve clojure.core$constantly$fn__4614. further. It gets transformed by the reader into a call to clojure.core$constantly$fn__4614clojure.core$constantly$fn__4614 class constructor with no parameter.
As you have seen above the constructor of that class requires exactly one constructor thus the compilation fails (in clojure.lang.Compiler.NewExpr constructor body) with:
java.lang.IllegalArgumentException: No matching ctor found for class clojure.core$constantly$fn__4614
I am not sure why the Clojure reader transforms the function value to a symbol with constructor call interop form and causing such behaviour thus I presented only the direct cause of the error message and not the root cause why your code doesn't work. I guess it might be a bug or it was a conscious design decision. From the macro authors it would be better to fail fast and learn that the return value of a macro is not a valid code data but on the other hand it might be very difficult or impossible to determine if the returned data is a valid code or not. It's worth checking on Clojure mailing list.
I think what is going on is: macros resolve before functions.
So if you call macroexpand-1 on the function you get:
(def test-constantly-fn (clojure.core/fn ([] ((produce-constantly-fn)))))
Thus ((produce-constantly-fn)) is called before function and gives listed error.
I have this macro:
(defmacro widget [msg-type value & app-key]
`(defrecord ~msg-type [~value]
Message
(~'process-message [msg# app#]
(let [state# (~#app-key app#)]
(dissoc
(->>
(merge state# msg#)
(assoc app# ~#app-key))
:errors)))))
Message is a protocol defined in a clojurescript dependency, with a process-message function.
When I try to use widget like so
(ns my.cljs.ns
(:require-macros [my.ns.macros :as macro])
(:require [petrol.core :refer [Message]]))
(macro/widget A-Record a-field :a-key)
I get this error:
Bad method signature in protocol implementation,
my.ns.macros/Message does not declare method called
process-message ...
How can I get Message to refer to petrol/Message instead of my.ns.macros/Message?
You need the power of the mystical ~' operator :)
I see you already invoked it for process-message, so perhaps you are already acquainted with why; but for the purposes of the answer, stuff in the backtick gets fully namespace qualified, where as evaluate quote puts the literal symbol in place.
(macroexpand-1 '(widget :a :b))
And the error message indicate that you need to ~'Message if you want to avoid it having the current ns attached to it.
However fully qualifying Message with the petrol namespace would be a good move IMO
petrol.core/Message
That way you don't need to rely on it being referred in the ns declaration. Note you don't need to ~' it either.
Also I would be wary of (~#app-key app#) because app-key are optional... you could get nothing passed in which would call whatever #app is, which doesn't sound like something you want to happen. Similarly passing more than one seems wierd to. Maybe it should be a required param?
Often I need to undefine a function in clojure. If I define something with defn how can I undefine it?
There is no one-argument version, because the same Var can be mapped in more than one namespace. If you are working from the REPL, you often want to unbind from the user namespace, e.g.
(ns-unmap 'user 'symbol-to-unbind)
The first argument to ns-unmap can be a symbol or a namespace, and the second argument should be a symbol.
I think, that you can use ns-unmap to do this.
P.S. Couldn't add this code into comment, so i put it here. To unmap function in current namespace, you need to use following code:
(ns-unmap *ns* 'method)
If you have:
(def x 42)
It might be useful to unbind the var:
(.unbindRoot #'x)
Now, if you try this
x
You get:
#<Unbound Unbound: #'user/x>
Would it be possible to override the 'require' command so that it will try to download a certain resource if it was not found on the local machine. For example:
(require 'examples.introduction)
; if not found => download from the net
; (url: http://media.pragprog.com/titles/shcloj/code/examples/introduction.clj)
You could override the require function and of course the overriden variant could download stuff if the namespace it was asked for is not available on the classpath. Overriding the way :require works in (ns ...) forms is, AFAIK, impossible for now due to the way in which ns is handled.
Note that such a 'downloading require' wouldn't be very helpful if you wanted to place new paths on the classpath (including new jars), as classpath injection doesn't work reliably in Clojure (due to JVM issues). There is clojure.core/add-classpath... but it's been marked as deprecated since forever now, its use is strongly discouraged, there are no guarantees that it will work for you and this situation isn't likely to change anytime soon. On the other hand, if you wanted to put new source files in a directory which was already present on the classpath, then that should work fine.
In case you do want to play around with overriding require, if you have a foo namespace, you could do
(ns foo
(:refer-clojure :exclude [require])
; other stuff; any :requires here will work as usual!
)
Then define your own require, using clojure.core/require when appropriate:
(defn require [ns-symbol]
(do-stuff-to-obtain-the-namespace))
clojure.contrib.find-namespaces namespace might be helpful in finding out what's available on the classpath. (Or you could use the the-ns function and see if it throws an exception after an initial attempt at requiring the namespace through clojure.core/require.)
Note that the binding approach which might come to mind first ((binding [require ...] ...)) will not work, since require normally resolves to a Var interned in the clojure.core namespace and Vars from namespaces whose names start with clojure are currently directly linked by the compiler (meaning no actual Var lookup is performed at runtime, so rebinding of those Vars has no effect on the code).
The (:refer-clojure :exclude [require]) in the ns form for your namespace prevents require from resolving to clojure.core/require and leaves you free to define a Var of that name in your own namespace. As mentioned above, that doesn't prevent the clojure.core/require Var from being accessible if you type out the fully qualified the symbol.
Actually, (add-classpath "http://foo/bar/baz/src/") or (add-classpath "http://www.foo.com/bar.jar"), will allow requiring remote stuff.
MichaĆ's warnings do apply though: Only use this for toying at the repl ...