With Clojure 1.9-beta2, the reader and writer now support a compact syntax for maps. The syntax avoids repeating the namespace in the case where all the keys are qualified keywords with the same namespace:
> (pr-str {:a/foo 1 :a/bar 2})
"#:a{:foo 1, :bar 2}"
That causes problem when sending such a serialized map to a Clojure 1.8 process: the old reader running there will fail to read it and throw a java.lang.RuntimeException: Reader tag must be a symbol.
Luckily, the printer only does this when the dynamic variable *print-namespace-maps* is truthy, and it's falsey by default, so my app continues to work in production. However, the REPL sets it to true, so when I work in the REPL and do something that ends up sending a request to a Clojure 1.8 service, it fails. How can I disable the new syntax in the REPL also?
I thought that maybe I could just (set! *print-namespace-maps* false) in my repl or add {:user {:repl-options {:init (set! *print-namespace-maps* false)}}} to my ~/.lein/profiles.clj, but that doesn't seem to work. I think the reason may be that the REPL uses binding to create thread-local bindings for a bunch of variables including this one, and set! does not work for local variable bindings.
You can redefine print-method for maps, which should work regardless of environment.
(defmethod print-method clojure.lang.IPersistentMap [m, ^java.io.Writer w]
(#'clojure.core/print-meta m w)
(#'clojure.core/print-map m #'clojure.core/pr-on w))
Using (set! *print-namespace-maps* false) works for me. (But this is some 5 years later.)
This also works, and can sometimes be more desirable:
(binding [*print-namespace-maps* false]
(pr-str {:a/foo 1 :a/bar 2}))
=> "{:a/foo 1, :a/bar 2}"
Related
I want to have a *flag* variable in a given namespace that is set to true only when :aot compiling.
Is there a way to do that?
Your issue is kind of complicated because the definition of Clojure's own dynamic nature, so there's no rough equivalent of C's #ifdef or some other mechanism that happens at compile time, but here's a workaround:
I created a Leiningen project with lein new app flagdemo. This trick detects when AOT is performed, as #Biped Phill mentioned above, using the dynamic var *compile-files*, and saves a resource in the classpath of the compiled code:
The code looks like this:
(ns flagdemo.core
(:gen-class))
(def flag-path "target/uberjar/classes/flag.edn")
(defn write-flag [val]
(try (spit flag-path (str val)) (catch Exception _)))
(defn read-flag []
(some-> (clojure.java.io/resource "flag.edn") slurp clojure.edn/read-string))
(write-flag false)
(when clojure.core/*compile-files*
(write-flag true))
(defn -main
[& args]
(println "Flag is" (read-flag)))
So, when the file loads using, say, lein run or when you load it in the REPL, it will try to write an EDN file with the value false.
When you compile the package using lein uberjar, it loads the namespace and finds that *compile-files* is defined, thus it saves an EDN file that is packaged with the JAR as a resource.
The function read-flag just tries to load the EDN file from the classpath.
It works like this:
$ lein clean
$ lein run
Flag is nil
$ lein uberjar
Compiling flagdemo.core
Created /tmp/flagdemo/target/uberjar/flagdemo-0.1.0-SNAPSHOT.jar
Created /tmp/flagdemo/target/uberjar/flagdemo-0.1.0-SNAPSHOT-standalone.jar
$ java -jar target/uberjar/flagdemo-0.1.0-SNAPSHOT-standalone.jar
Flag is true
Credit to #Biped Phill and #Denis Fuenzalida for explaining it to me.
I think this works as well:
(def ^:dynamic *static* false)
(when (and *compile-files* boot/*static-flag*)
(alter-var-root #'*static* true))
then in profiles.clj:
:injections [(require 'boot)
(intern 'boot '*static-flag* true)]
First you need to indicate that a variable will change over time:
(def ^:dynamic *the-answer* nil)
*the-answer*
;=> nil
The ^:dynamic bit will allow that variable to be rebound later:
(binding [*the-answer* 42] *the-answer*)
;=> 42
ADDENDUM 1
Here's what would happen if you didn't use ^:dynamic:
(def *the-answer* nil)
(binding [*the-answer* 42] *the-answer*)
;=> [...] Can't dynamically bind non-dynamic var [...]
ADDENDUM 2
These kind of variables are commonly referred to as "earmuffs". The naming convention is unenforced but strongly encouraged.
Here's what happen in the REPL when you use this naming without declaring a dynamic variable:
(def *the-answer* nil)
; Warning: *the-answer* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *the-answer* or change the name. (/tmp/form-init7760459636905875407.clj:1)
Is it ok to use binding with core.async? I'm using ClojureScript so core.async is very different.
(def ^:dynamic token "no-token")
(defn call
[path body]
(http-post (str host path) (merge {:headers {"X-token" token}} body)))) ; returns a core.async channel
(defn user-settings
[req]
(call "/api/user/settings" req))
; elsewhere after I've logged in
(let [token (async/<! (api/login {:user "me" :pass "pass"}))]
(binding
[token token]
(user-settings {:all-settings true})))
In ClojureScript1, binding is basically with-redefs plus an extra check that the Vars involved are marked :dynamic. On the other hand, gos get scheduled for execution1 in chunks (that is, they may be "parked" and later resumed, and interleaving between go blocks is arbitrary). These models don't mesh very well at all.
In short, no, please use explicitly-passed arguments instead.
1 The details are different in Clojure, but the conclusion remains the same.
2 Using the fastest mechanism possible, setTimeout with a time of 0 if nothing better is available.
In Clojure, adding custom reader tags is really simple
;; data_readers.clj (on classpath, eg. src/clj/)
{rd/qux datareaders.reader/my-reader}
;; Define a namespace containing the my-reader var:
(ns datareaders.reader)
(defn my-reader [x] 'y)
;; use special tag in other namespace. Readers have to be required first.
(require 'datareaders.reader)
(defn foo [x y]
(println #rd/qux x "prints y, not x due to reader tag."))
I am trying to achieve the same thing for ClojureScript but am getting an error that #rd/qux is not defined. I am using lein cljsbuild once to build the project. Is that a limitation of ClojureScript or is it that cljsbuild builds the project before the readers have been resolved? In that case, how can I force leiningen to load the readers namespace before cljsbuild is started?
EDIT: Note that this example intends to use reader tags within ClojureScript source code and not when reading auxilliary data via read-string.
This currently isn't possible, but will be as soon as #CLJS-1194 and #CLJS-1277 are fixed. Hopefully that will happen very soon.
If you wanted to do it, just rename data_readers.clj to data_readers.cljc and use conditional readers.
As an aside, what's your use case for this?
Both #CLJS-1194 and #CLJS-1277 are fixed, so this should work as expected.
The mechanism to add a custom reader tag in cljs is different. You have to call register-tag-parser! which takes a tag and a fn.
From the cljs reader tests:
(testing "Testing tag parsers"
(reader/register-tag-parser! 'foo identity)
(is (= [1 2] (reader/read-string "#foo [1 2]")))
Your example would be:
(cljs.reader/register-tag-parser! 'rd/qux (fn [x] 'y))
(defn foo [x y]
(println #rd/qux x "prints y, not x due to reader tag."))
I'm currently reading the Clojure Programming book, and following the examples. However I come across an error.
(defn print-logger
[writer]
#(binding [*out* writer]
(println %)))
(def *out*-logger (print-logger *out*))
(*out*-logger "hello")
Will result in: `Can't dynamically bind non-dynamic var: user/out
I'm very new to Clojure, and don't understand why this happens, especially when I'm following the example :)
The issue is not in the code sample you have.
*out* should refer to clojure.core/*out*, so if you are running this in a repl you might have run something previous, to what you have, like (def *out* something) to create a user/*out*.
Then, when you defined your print-logger function, the (binding [*out* writer] ...) statement would be trying to rebind user/*out* instead of clojure.core/*out*.
You can use ns-unmap to remove user/*out* from your namespace.
(ns-unmap 'user '*out*) ;; => nil
You will also need to define your print-logger function again to recapture the correct clojure.core/*out*.
I'm relatively new to Clojure and going through the Clojure chapter in Seven Languages in Seven Weeks, and I can't figure out why this code from the book isn't working for me. I'm using Leiningen and Clojure version 1.5.1. As far as I can tell after careful checking, I typed the code exactly as it reads in the book.
Here is the code:
(ns seven-languages.compass)
(defprotocol Compass
(direction [c])
(left [c])
(right [c]))
(def directions [:north :east :south :west])
(defn turn [base amount]
(rem (+ base amount) (count directions)))
(defrecord SimpleCompass [bearing]
Compass
(direction [_] (directions bearing))
(left [_] (SimpleCompass. (turn bearing 3)))
(right [_] (SimpleCompass. (turn bearing 1)))
Object
(toString [this] (str "[" (direction this) "]")))
I'm running "lein repl" from within the directory ~/clojure/seven-languages (created by running "lein new seven-languages" in ~/clojure). Relative to this directory, my .clj files are in src/seven_languages. So far I've been able to successfully import and use them from the repl by typing (use 'seven-languages.filenamehere).
So, after saving the code I listed above as src/seven_languages/compass.clj, I run this from the REPL:
user=> (use 'seven-languages.compass)
nil
But then when I try to define an "instance" of the SimpleCompass, typing it exactly like in the book, this happens:
user=> (def c (SimpleCompass. 0))
CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: SimpleCompass, compiling:(NO_SOURCE_PATH:1:8)
I also tried loading the file using (load-file "src/seven_languages/compass.clj"), but got the same results. Since the actual loading seemed to work as expected, I wonder if there has been some change in how defprotocol or defrecord works in versions of Clojure subsequent to when Seven Languages in Seven Weeks was written. In the introduction to the Clojure chapter, the author writes, "I’m using a prerelease version of Clojure 1.2, and it should be fully ready by the time this book is in your hands."
Can anyone tell why this code isn't working properly? If it's a version issue, how would you update this code for Clojure 1.5.1?
EDIT: Aha! I figured it out after finding this:
Clojure - deftype ignored - unable to resolve classname on tests
It's a namespace issue. I'm guessing this is a change since version 1.2 when 7LI7W was written. For whatever reason, while functions in imported files are "automatically handled" so that you can just use them directly, types are not automatically handled. You have to include the full path to the type, and make sure you use the actual path with underscores, not hyphens. I got my code to work by substituting SimpleCompass with the full path, seven_languages.compass.SimpleCompass:
user=> (def c (seven_languages.compass.SimpleCompass. 0))
#'user/c
user=> c
#seven_languages.compass.SimpleCompass{:bearing 0}
user=> (left c)
#seven_languages.compass.SimpleCompass{:bearing 3}
user=> (right c)
#seven_languages.compass.SimpleCompass{:bearing 1}
Apart from always fully qualifying the class name, you can import it and use the short name afterwards:
(import seven_languages.compass.SimpleCompass)
;; (SimpleCompass. 0) etc. will work now
Also, it's worth pointing out that defrecord creates to factory functions for you, one positional and one taking a map:
(defrecord Foo [x])
(->Foo 1)
;= #user.Foo{:x 1}
(map->Foo {:x 1})
;= #user.Foo{:x 1}
These are just regular functions and so will have been pulled in by your use call.
Relatedly, deftype, as of Clojure 1.5.1, creates the positional factory only.