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)).
clojure.core/read is used to read "code" by Clojure itselfclojure.edn/read is used to read "data" (EDN)read-line is used to read text lines as string; it's your problem to
decipher themread do for youread 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.
readUsually 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.
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* .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With