Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does `read` return a symbol when `read-line` returns a string

Tags:

clojure

I'm learning Clojure by following the Hackerrank 30 days of code, and lost some hours due to a behavior I neither understand nor found any documentation or explanation about:

  • (read) returns a symbol:

    user=> (def key-read (read))
    sam
    #'user/key-read
    user=> (type key-read)
    clojure.lang.Symbol
    
  • (read-line) returns a string

    user=> (def key-line (read-line))
    sam
    #'user/key-line
    user=> (type key-line)
    java.lang.String
    

As a result, parsing a line with (read) (read) to get map keys and values results in the keys to be symbols, than will never be matched by a further (read-line).

Why is this so? And also, where can I find the return value? (this is not documented in (doc read)).

like image 818
Joël Avatar asked Nov 17 '25 09:11

Joël


1 Answers

TL;DR

  • clojure.core/read is used to read "code" by Clojure itself
  • clojure.edn/read is used to read "data" (EDN)
  • read-line is used to read text lines as string; it's your problem to decipher them

What can read do for you

read does not only read symbols, but anything, that Clojure uses to represent code. If you give it a symbol to parse, it will give you symbol back:

(type (read))
test
clojure.lang.Symbol

But also other things

(type (read))
5
java.lang.Long

(type (read))
{:a 42}
clojure.lang.PersistentArrayMap

(type (read))
"hello"
java.lang.String

So you can get back a string with read too, if you feed it a string.

real-world use of read

Usually read is used by Clojure itself and that's it. Reading EDN is usually done using clojure.edn/read, which does not allow code execution and therefor is no security risk if handling EDN from untrusted sources.

docs

For good measure, here are the docs:

(doc read)
-------------------------
clojure.core/read
([] [stream] [stream eof-error? eof-value] [stream eof-error? eof-value recursive?] [opts stream])
  Reads the next object from stream, which must be an instance of
  java.io.PushbackReader or some derivee.  stream defaults to the
  current value of *in*.

  Opts is a persistent map with valid keys:
    :read-cond - :allow to process reader conditionals, or
                 :preserve to keep all branches
    :features - persistent set of feature keywords for reader conditionals
    :eof - on eof, return value unless :eofthrow, then throw.
           if not specified, will throw

  Note that read can execute code (controlled by *read-eval*),
  and as such should be used only with trusted sources.

  For data structure interop use clojure.edn/read

(doc read-line)
-------------------------
clojure.core/read-line
([])
  Reads the next line from stream that is the current value of *in* .
like image 168
cfrick Avatar answered Nov 19 '25 03:11

cfrick



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!