is it intentional that spec/keys will check the :opt-un keys of a map? it's nice that it works, but the docstring merely says that :opt is only for documentation and that there's -un versions.
Yes
Is there a reader affordance for reading an entire form from input stream without, for instance, resolving aliases? (For context, nrepl.transport/tty, https://github.com/nrepl/nrepl/pull/387.)
The following example accomplishes it, but relies on internal LispReader$Resolver which didn’t arrive until 1.10 (nrepl builds for 1.8 & 1.9).
(with-open [in (-> ":keyword (next-form)"
(.getBytes "UTF-8")
io/input-stream
io/reader
(clojure.lang.LineNumberingPushbackReader.))]
(binding [*reader-resolver* (reify clojure.lang.LispReader$Resolver
(currentNS [_] (gensym))
(resolveAlias [_ _alias-sym] (gensym))
(resolveClass [_ _class-sym] (gensym))
(resolveVar [_ _var-sym] (gensym)))]
(second (read+string {:read-cond :preserve} in))))$ clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.9.0"}}}' -M -e 'clojure.lang.LispReader$Resolver'
clojure.lang.LispReader$Resolver
nrepl dropped support for 1.8 and 1.9 AFAIK? at least CIDER did
you can use another library, like tools.reader or edamame, but I guess you're looking for something built-in?
this is the purpose of Resolver so I'd say that's definitely the intended approach for the reader
We removed 1.7, but 1.8 is honestly not in big demand either. Can phase it out.
Which would leave 1.9. I’ll check out what edamame has to offer.
I would advise against going that route, as we strongly prefer nREPL staying deps-free.
It is OK, however, to not support this particular bit of functionality on Clojure 1.8 and 1.9
Thanks! I’ll see what I can do within these constraints.
I just showed that this class is available in 1.9?
Yes, you are correct @borkdude. Thanks.
Sadly, Unable to resolve symbol: read+string in 1.9 context.
@frankleonrose You can probably replace read+string with some input stream proxy that captures read bytes for later. Some LLM can help for sure.
quickly whipped this up:
(set! *warn-on-reflection* true)
(defn string->input-stream
[^String s]
(java.io.ByteArrayInputStream. (.getBytes s "UTF-8")))
(defn read+string*
"Reads one form from input-stream, returning [form string-read]."
[^java.io.InputStream is]
(let [sb (StringBuilder.)
base (java.io.InputStreamReader. is "UTF-8")
rdr (java.io.PushbackReader.
(proxy [java.io.Reader] []
(read
([] (let [c (.read base)]
(when (not= -1 c)
(.append sb (char c)))
c))
([^chars cbuf ^long off len]
(let [n (.read base cbuf off len)]
(when (pos? n)
(.append sb cbuf off n))
n)))
(close [] (.close base))))
form (read rdr)]
[form (str sb)]))
(prn (read+string* (string->input-stream "#_{} ;; dude
(+ 1 2 3) (assoc {} :foo :bar)")))
;; => [(+ 1 2 3) "#_{} ;; dude\n (+ 1 2 3)"]what would be a test case to test if the unread on a pushbackreader would work ok here?
But honestly, I'd just skip this feature for 1.9, let it stay "broken" the way it is now
yeah or drop support for 1.9 completely
That too. nREPL is kinda foundational though, and you never know how people might use it. 1.8 is the last pre-spec and pre-clojure-split version, so there might still be people relying on these characteristics somewhere
btw why was the reader resolver needed, isn't it a matter of setting *ns* correctly?
(ns prior
(:require [clojure.set :as set]))
(ns other)
(binding [*ns* (find-ns 'prior)]
(prn (read-string "::set/dude")))IIRC, the tty transport is a weird amalgamation of streaming (tty) and nrepl (message-based). Reading is needed just for framing, to split the text stream and then feed to nrepl server chunk by chunk. Doing what you suggest requires back-n-forth, communicating the "current namespace" back from nrepl server to the tty transport. Probably doable too, but I can't tell what is easier without looking.
ok
Updated example above to return (gensym) for unused resolved symbols. It avoids duplicate key error when parsing forms like {::foo/x 1 ::bar/x 1}.
Many thanks for https://clojure.atlassian.net/browse/CLJ-2359?focusedCommentId=50541, @borkdude!
I feel like I'm going insane... since when is (= 0.0 0) ;=> false?
float vs integer are never equal
registry=> (= 0 0.0)
false
registry=> (= 0M 0.0)
false
registry=> (= 0M 0N)
falsethere are many zeros
but
registry=> (doc ==)
-------------------------
clojure.core/==
([x] [x y] [x y & more])
Returns non-nil if nums all have the equivalent
value (type-independent), otherwise false
nil
registry=> (== 0 0.0)
trueI remember people doing a whole bunch of work to make sure the hash codes were the same? Ah... OK
normal caveats of floats though
registry=> (== 0.3 (+ 0.1 0.2))
falseThe docs for = say: "compares numbers and collections in a type-independent manner"
hard to parse
how does that distribute?
“compares numbers and also compares collections in a type independent manner” or “compares numbers type independent and compares collectiosn type independent”
ermm, the first interpretation suggests it wouldn't compare, e.g. strings, or symbols, or ...
Oh... I see, it could be that it specially handles numbers.
Still, that doesn't seem like the natural interpretation.
ok. i think the type independent equality is there
(= (short 1) (long 1))
truebut it doesn’t cross categories
(= (short 1) (long 1) 1N)
true(= (short 1) (long 1) 1N (int 1))
trueAh, OK, so https://clojure.org/guides/equality does explicitly call out that they need to be the same category.
fun thread to go down. I suspect that’s an @andy.fingerhut document . He’s done some really great things like this
clojure.core/=
([x] [x y] [x y & more])
Equality. Returns true if x equals y, false if not. Same as
Java x.equals(y) except it also works for nil, and compares
numbers and collections in a type-independent manner. Clojure's immutable data
structures define equals() (and thus =) as a value, not an identity,
comparison.
I'm still not sure how to interpret "numbers" in this docstring though.(have to run, though)
can you write a question that you don’t know how to answer?
= and floats, name a more iconic duo
Yes, the equality document was me trying to carefully and thoroughly present the full behavior of clojure.core/=, along with a few other related things like clojure.core/hash , warts and all.
(different people may have different opinions of what parts should be considered "warts" vs. not, of course).