Reputation: 2822
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)
).
Upvotes: 2
Views: 261
Reputation: 37008
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.
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.
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* .
Upvotes: 7
Reputation: 29958
The other 2 answers are good. I didn't even know that clojure.core/read
existed!
I only wanted to add in a list of my favorite documentation sources. Please review & study the Clojure CheatSheet, which links to examples on clojuredocs.org.
Unfortunately, the API docs at clojure.org are not as descriptive and it is harder to find things unless you already know the name and location.
Upvotes: 1
Reputation: 1281
You can find the Clojure API documentation at https://clojure.github.io/clojure/clojure.core-api.html. Both read
and read-line
are there.
Your specific goal isn't quite clear, but in general, application software prefers read-line
and parses the results in whatever way makes sense... perhaps with re-matches
for regular expressions. Clojure itself reads program code with read
.
Upvotes: 1