Not sure if this is a bug or feature but clojure.edn violates EDN format specification:
user=> (clojure.edn/read-string {:readers {'foo (fn [val] (prn "!!!") val)}} "#_ #foo [1 2 3]")
"!!!"
Execution error at user/eval176 (REPL:1).
EOF while reading
There are two problems:
1. The custom reader function is called even when inside a discard
2. I did not expect an EOF error in this casei updated the patch today to cover discarded aliased keywords and aliased keywords in skipped reader conditional branches
i expanded the https://clojure.atlassian.net/browse/CLJ-2928 and attached a patch
discard impl does an ordinary read, then throws away the result
two consequences to this: reading tagged forms invokes their handlers, and aliases are resolved
e.g. not being able to discard an invalid/keyword
there are JIRA(s?) about this
2. #_ discards the next form, which is a tagged vec
the tag is not a separate form
there is nothing after the tagged vec to read
This feels a bit inconsistent though:
user=> (clojure.edn/read-string "#_1")
nil
user=> (clojure.edn/read-string {} "#_1")
Execution error at user/eval170 (REPL:1).
EOF while readinguser=> (clojure.edn/read-string "#_ #inst \"2027-06-06\"")
nil
also I can't see a connection between alias resolution and invocation of custom reader fn
yes that violates my expectations. all should eof
docstring says: > Reads one object from the string s. Returns nil when s is nil or empty
alias resolution and tag handler fns are both examples of things not needing to happen when discarding
oh -- then no. all should do that
didn't realize that read-string promised that!
here it passes explicitly nil, but when not providing eof explicitly it doesn't default to nil:
([s] (read-string {:eof nil} s))
([opts s] (when s (clojure.lang.EdnReader/readString s opts))))(I almost never use read-string, and made an incorrect assumption, editing my messages above)
Unsure if questions still open here…
Not sure what you mean by opening questions, but either the docstring has to change or the impl I guess?
and since the latter would be breaking, probably changing the docstring is safest
is changing a throw to not throw a breaking change?
I'd say so
I mean, depends on the context, but here it's a default option to throw on EOF
people might have try/catch-ed this - changing it to return nil would break them
> Unsure if questions still open here… and what about calling reader fns inside discard?
What about it?
Discard reads, then discards
https://github.com/edn-format/edn?tab=readme-ov-file#discard according to spec it is an error if user supplied reader function is called inside discard
> A reader should not call user-supplied tag handlers during the processing of the element to be discarded. That's interesting
Is this a question about clojure.edn readers or clojure.core
clojure.edn
It sounds like there are maybe two questions here. It would be helpful to fully restate those two questions, perhaps in ask Clojure questions
sure
https://ask.clojure.org/index.php/14761/clojure-supplied-functions-tagged-literal-discarded-discard
despite from this being different from the docs, I wonder why this is important to you - are you increasing a counter while the tag function is executed or so?
bugs are bugs and worth fixing
I work on C implementation for EDN parser where primary goal is to pedantically follow edn-format/edn specification by default (optionally extend to clojure.edn capabilities) I found this specific line interesting and tried behaviour of fast-edn.core first (reported as a bug), then later I discover that clojure.edn is doing the same thing
I'm not saying it shouldn't be aligned with the docs. But learning why this bugs someone is worth informing other things
(FWIW, edamame also just calls reader functions while in discard mode)
(edamame is EDN by default, but can be tuned up to full clojure, so it's a grey area)