clojure-dev 2025-11-20

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 case

i updated the patch today to cover discarded aliased keywords and aliased keywords in skipped reader conditional branches

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 reading

user=> (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)

Alex Miller (Clojure team) 2025-11-20T14:41:04.030969Z

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 mean, depends on the context, but here it's a default option to throw on EOF

👍 1

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?

Alex Miller (Clojure team) 2025-11-20T14:47:59.847219Z

What about it?

Alex Miller (Clojure team) 2025-11-20T14:48:42.546749Z

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

Alex Miller (Clojure team) 2025-11-20T14:50:42.133499Z

Is this a question about clojure.edn readers or clojure.core

clojure.edn

Alex Miller (Clojure team) 2025-11-20T14:51:49.143759Z

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

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

👍 1

(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)