Giter Club home page Giter Club logo

Comments (3)

raszi avatar raszi commented on June 6, 2024 4

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.

raszi avatar raszi commented on June 6, 2024

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.

xpe avatar xpe commented on June 6, 2024

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:

  1. (type (keyword "x y")) evaluates to clojure.lang.Keyword.
  2. (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:

  1. 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"

  2. 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".

  3. 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! :)

  4. 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! :)

  5. 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 to clojure.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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.