Clojure: read-string on functions - clojure

Is there a way to use the reader with function values, e.g:
(read-string (pr-str +))
RuntimeException Unreadable form clojure.lang.Util.runtimeException
(Util.java:219)
?

As you might already know the output for (pr-str +) is not valid Clojure code that the reader can parse: "#<core$_PLUS_ clojure.core$_PLUS_#ff4805>". The output for function values when using the functions pr, prn, println and such, is intentionally wrapped around the #< reader macro that dispatches to the UnreadableReader, which throws the exception you are seeing.
For the example you provided you can use the print-dup function that works for basic serialization:
(defn string-fn [f]
(let [w (java.io.StringWriter.)]
(print-dup f w)
(str w)))
(let [plus (read-string (string-fn +))]
(plus 1 2))
The serialization done for the + function is actually generating the call to the class' constructor:
#=(clojure.core$_PLUS_. )
This only works of course if the class is already compiled in the Clojure environment where you are reading the string. If you serialized an anonymous function, saving it to a file and then reading it back in, when running a new REPL session, it will most likely not work since the class name for each anonymous function is different and depends on Clojure internals.
For arbitrary functions things get a lot more complicated. Sharing the source code might not even be enough, the function could rely on the usage of any number of other functions or vars that only exist in the source environment. If this is what you are thinking of doing, maybe considering other approaches to the problem you are trying to solve, will eliminate the need to serialize the value of arbitrary functions.
Hope it helps,

If you only need the name, can you just send the symbol with (name '+).
But generally speaking, it is a bad idea to use clojure read, if you want to read it back, as clojure's reader might execute some code in the process. Maybe have a look at the edn reader : clojure.edn/read-string
But maybe you just need to convert the string back to a symbol, in which case the (symbol name) function would be enough.

Related

Calling a private macro from another namespace in Clojure?

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.

why are compojure routes defined as macros?

for example the Luminus website states that
Compojure route definitions are just functions that accept request
maps and return response maps...
(GET "/" [] "Show something")
...
But compojure routes are not functions
(defmacro GET "Generate a `GET` route."
[path args & body]
(compile-route :get path args body))
One can use the function make-route that returns a functions, but does not allow for destructuring. So as a function you can not use compojure's special syntax for destructing (i.e the vector) but does this stop any form of destructuring? Does the macro from given them a performance increase?
(make-route :get "/some_path" some_handler)
Couldn't the destructing syntax be passed to the function using a macro wrapper?
One reason macros are used is so the user can write function and symbol names without having to quote everything. Take this example from the Clojure Cookbook:
; Routing
(defroutes main-routes
(GET "/" [] (index))
(GET "/en/" [] (index))
(GET "/fr/" [] (index-fr))
(GET "/:greeting/" [greeting] (view greeting)))
All of the index* symbols, plus view and greeting would have to be quoted if GET were a function:
; Routing
(defroutes main-routes
(GET "/" [] '(index))
(GET "/en/" [] '(index))
(GET "/fr/" [] '(index-fr))
(GET "/:greeting/" '[greeting] '(view greeting)))
Since function arguments are evaluated before the function is invoked, (index) et al would be evaluated as soon as the form was read. Also, the greeting arg will be changing on each HTTP request, so it obviously is not known ahead of time.
The macro also takes care of all the destructuring magic which is not (normally) possible with a regular function.
The thing which is often confusing (and is not well explained to beginners) is that a line like:
(GET "/:greeting/" [greeting] (view greeting))
is not normal "Clojure code". Instead, it is a type of shorthand (Domain-Specific Language or DSL to be precise) that the GET macro will ingest and use as instructions on how to generate "legal" Clojure code. The DSL is normally much shorter, simpler, & more convenient for a human than the final generated code, just as Clojure is much shorter, simpler, & more convenient than the Java Bytecode produced by the Clojure compiler, or the machine assembly language code eventually produced by the JVM.
In short, each macro is a "pre-compiler" that turns the DSL into plain Clojure, which is then ingested by the Clojure compiler to generate Java bytecode.
Having said that, it could be re-arranged to put all of the macro magic into the defroutes macro so that the GET symbol was neither a function nor a macro, but just a type of marker like the :get keyword in the implementation. As a user, these kinds of implementation details normally don't matter much.
Update
It is best to use macros only when a function won't work or is very awkward. The deciding factor is usually if one wants to use bare (unquoted) symbols, but not evaluate them in advance. Core Clojure itself uses macros for many constructs that are "built-ins" in other languages, including defn, for, and, or, when, and others.
Also note that a macro cannot do some things a function can, such as being a parameter to a higher-order function like filter.
In summary, a function defines a behavior. A macro defines a language extension.

Wrapper-macro tactic over extend-type in Clojure failed

I've reduced my bigger problem to an artificial MVE (minimal viable example)
using file-io for illustration. My question concerns a certain wrapper macro
that I explain below; it does not concern better ways to use the file-io APIs;
I'm just using file-io to illustrate the macro problem in a small and easy
context. The wrapper macro tactic in my real problem is harder to show and
explain, but this MVE captures the gist of the problem.
Consider the following protocol:
(defprotocol Dumper
(dump [this]))
and an implementation over java.io.File
(extend-type java.io.File
Dumper
(dump [file]
(with-open [rdr (io/reader file)]
(doseq [line (line-seq rdr)]
(println line)))))
where we have done a (:use [clojure.java.io :as io]) to get the reader
function. I can use this as follows:
(defn -main
[& args]
(dump (io/file "resources/a_file.txt")))
Hello from a text file.
Now, I want to create another implementation of the protocol, this time over
java.lang.String. This implementation wraps the string, treating it as a
file-path string; creates a clojure.java.io/file; then calls into the other
implementation of the protocol:
(extend-type java.lang.String
Dumper
(dump [path-str] (-> path-str, io/file, dump)))
and call it like this:
(defn -main
[& args]
(dump (io/file "resources/a_file.txt"))
(dump "resources/a_file.txt"))
Hello from a text file.
Hello from a text file.
In my real problem, I have many functions in the protocol, and one
implementation just wraps the other in the manner shown. Notice that, in the
wrapper implementation, the method name, dump, is replicated. Let's eliminate
that replication with a macro (it's worth doing when the real protocol has many
methods):
(defmacro wrap-path-string [method]
`(~method [path-str] (-> path-str, io/file, ~method)))
(extend-type java.lang.String
Dumper
(wrap-path-string dump))
Oops, the compiler doesn't like it:
Exception in thread "main" java.lang.UnsupportedOperationException:
nth not supported on this type: Symbol, compiling:(wrapper_mve/core.clj:18:1)
at clojure.lang.Compiler.analyze(Compiler.java:6688)
at clojure.lang.Compiler.analyze(Compiler.java:6625)
at clojure.lang.Compiler$MapExpr.parse(Compiler.java:3072)
I tried macroexpand-all'ing and macroexpand-1'ing the macro calls (in CIDER,
difficult to replicate here), and it looks ok. I'm at a loss how to debug
deeper, but perhaps someone here can spot the problem.
Again, I know this MVE has better solutions with the file-io APIs, but I really
want to debug the macro, not find ways to avoid using it, because I need the
wrapper-macro tactic in my real problem.
I believe the problem is that extend-type is itself a macro, and macroexpansion begins with the outermost form (as opposed to function evaluation, which evaluates each argument before invoking the function). In this case the macroexpansion of extend-type is trying to treat the form (wrap-path-string dump) as a function body, and is expecting the second item to be an arg vector but finds the symbol dump.
If you want to go this route, I think you'll need to write a macro that will produce the desired expand-type form with all the function bodies already expanded in place.

Why one function got from a macro works while another cannot be compiled?

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.

General syntax of multimethods

I apologize if the question is trivial, but some googling is not leading me anywhere. What is the general syntax of defmulti and defmethod? I can write simple multimethods, but I am not sure where I can put the docstring, pre and post conditions, metadata and so on.
I am actually interested in ClojureScript more than in Clojure, so if there are differences between the two, please tell me.
In a REPL you can use the doc function to get the function arguments and (most of the time) an explanation of the options. As for ClojureScript, these two functions are macros, which means they are expanded at compile time and should behave exactly as they do in regular Clojure. That is, as long as ClojureScript can handle the code the macro generates.
user=> (doc defmulti)
-------------------------
clojure.core/defmulti
([name docstring? attr-map? dispatch-fn & options])
Macro
Creates a new multimethod with the associated dispatch function.
The docstring and attribute-map are optional.
Options are key-value pairs and may be one of:
:default the default dispatch value, defaults to :default
:hierarchy the isa? hierarchy to use for dispatching
defaults to the global hierarchy
nil
user=> (doc defmethod)
-------------------------
clojure.core/defmethod
([multifn dispatch-val & fn-tail])
Macro
Creates and installs a new method of multimethod associated with dispatch-value.
nil
At Clojuredocs: defmulti, defmethod.
If you don't find the examples there detailed enough, you might consider adding your own (once you've gotten all your questions answered).