Comments (3)
An even crazier example which is also somehow related:
(clojure.edn/read-string (pr-str (into {} [[(keyword "a b c") "a"]])))
{:a b, c "a"}
from edn.
A sample code to reproduce the issue:
(clojure.edn/read-string (pr-str (into {} [[(keyword "a::b") "a"]])))
java.lang.RuntimeException: Invalid token: :a::b
from edn.
In reply to the comment by @raszi ...
For those that are surprised or perhaps confused by the example from @raszi that shows how (clojure.edn/read-string (pr-str (into {} [[(keyword "a b c") "a"]])))
evaluates to {:a b, c "a"}
.
Clarifying the keyword
function
Let's start with some basics. First, let's review the keyword
function. (doc keyword)
gives:
clojure.core/keyword
([name] [ns name])
Returns a Keyword with the given namespace and name. Do not use :
in the keyword strings, it will be added automatically.
I want to call attention to the part that says "a" keyword. To emphasize, only * one * keyword is returned.
Here are some correct and idiomatic uses of keyword
:
(keyword "foo")
=>:foo
(keyword "bar" "foo")
=>:bar/foo
Here is an obviously incorrect use: (keyword "bar" "foo" "extra")
gives
Execution error (ArityException) at user/eval163 (REPL:1).
Wrong number of args (3) passed to: clojure.core/keyword
Using keyword
in a perhaps confusing way
Now, let's talk about a valid but perhaps confusing use of keyword
. (I also consider the following example to be non-idiomatic or at least uncommon.) Consider (keyword "x y")
which prints :x y
at the REPL.
Aside: I did not say that (keyword "x y")
evaluates to :x y
-- that would be impossible, since y
is syntactically a symbol and in this context, undefined. You can verify this by trying (resolve 'y)
.
To return to the previous thread, (keyword "x y")
prints :x y
at the REPL. To be clear, :x y
is the printed representation of one keyword with the name "x y". You can easily verify this:
(type (keyword "x y"))
evaluates toclojure.lang.Keyword
.(name (keyword "x y"))
evaluates to"x y"
.
If you haven't seen name
before, here is the documentation, available by evaluating (doc name)
at the REPL:
clojure.core/name
([x])
Returns the name String of a string, symbol or keyword.
Similarly, (keyword "x y z")
evaluates to one keyword: :x y z
. This keyword has the name "x y z".
Revisiting the first example
Let's take this from smaller to larger:
-
Let's look at (a smaller piece of) the example that @raszi mentioned,
[(keyword "a b c") "a"]
. Based on what I showed above, we can reason through this and see that this will return a vector with two elements: (i) a keyword with the name":a b c"
and (ii) the string"a"
. Here is one way to demonstrate this:(clojure.string/join "<$>" [(keyword "a b c") "a"])
evaluates to":a b c<$>a"
-
Next, let's look at
(into {} [[(keyword "a b c") "a"]])
which prints as{:a b c "a"}
. This is a map with one key,:a b c
and one value,"a"
. -
What happens if you type
{:a b c "a"}
at the REPL? You'll get (my markdown markup added): "Syntax error compiling at (REPL:0:0). / Unable to resolve symbol:b
in this context". Conclusion: don't type this into the REPL! :) -
What should you type at the REPL instead? This:
{(keyword "a b c") "a"}
. You might say, "That's much less ambiguous" and you would be right! :) -
Next, let's look at
(pr-str (into {} [[(keyword "a b c") "a"]]))
which evaluates to"{:a b c \"a\"}"
. Based on number 3, above, if you pass this toclojure.edn/read-string
, you should not expect it to evaluate to the input value!
Conclusion
Using (clojure.edn/read-string (pr-str thing))
is not guaranteed to recover the thing
!
To state it in a different way, #(clojure.edn/read-string (pr-str %1))
is not the identity function. It appears to work that way in a vast majority of common cases, but it breaks down in some 'weird' ways. Caveat evaluator!
The Fun Doesn't Have to Stop here...
Read much more about this issue (and more) on this Clojure Google Group thread: How to escape a space in a keyword?.
from edn.
Related Issues (20)
- The edn spec inaccurately describes what characters are allowed in symbols. HOT 3
- json-ld, #iri HOT 1
- Ratio datatype is not part of the spec even though clojure.edn supports it. HOT 6
- Support for not-a-number or non-finite floating point values HOT 1
- Single-quote is not mentioned as a valid symbol character HOT 5
- Can Keywords contain escape characters? HOT 1
- Support for cyclic data HOT 2
- Tagged Elements Issue? HOT 3
- Make the spec concrete already HOT 5
- edn spec does not yet include namespace map syntax
- How are consumers supposed to handle values with unrecognized tags? HOT 1
- Reader flag to support unicode escapes in string literals HOT 2
- ns alias HOT 2
- Issue in the spec for keywords
- Alternative string quote syntax HOT 7
- An example of edn file HOT 1
- BNF is absent
- Provide a testsuite for EDN format
- JSON query results output option HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from edn.