This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-01-03
Channels
- # adventofcode (2)
- # announcements (1)
- # asami (35)
- # babashka (67)
- # beginners (97)
- # cherry (3)
- # clj-yaml (3)
- # cljsrn (9)
- # clojure (44)
- # clojure-dev (34)
- # clojure-europe (13)
- # clojure-gamedev (1)
- # clojure-norway (10)
- # clojure-uk (2)
- # clojurescript (24)
- # clr (1)
- # conjure (18)
- # cursive (4)
- # datalevin (3)
- # emacs (6)
- # graalvm (9)
- # graphql (1)
- # introduce-yourself (1)
- # malli (7)
- # nrepl (3)
- # portal (1)
- # quil (2)
- # reagent (1)
- # reitit (21)
- # releases (1)
- # reveal (11)
- # ring (2)
- # shadow-cljs (17)
- # sql (24)
- # vim (4)
I find this weird problem with overloads and Clojure. The two overloads differ in the middle argument type, the last argument type is always String, but unless I add ^String
to the last argument, reflection is used here and I get reflection warning
Reflection warning, /Users/....test.clj:20:11 - call to method appendReplacement on java.util.regex.Matcher can't be resolved (argument types: java.lang.StringBuilder, unknown).
Here’s a function:
(defn add-replacement [^StringBuilder base ^Matcher m replacement]
(.appendReplacement m modified replacement))
this will produce a warning
(defn add-replacement [^StringBuilder base ^Matcher m replacement]
(.appendReplacement m modified ^String replacement))
will notwhich makes absolutely no sense, because last argument type doesn’t vary between overloads
I see.
It does make sense, but only if you shift your perspective a bit.
As you can see, the actual warning is about not being able to resolve the method - not about not being able to disambiguate between two methods.
And that's because the last argument is of type unknown
. You haven't specified that it's a string, so it can be anything. And Clojure can't find a method that accepts anything.
It does it even with just one argument, with just one function with that name:
(set! *warn-on-reflection* true)
=> true
(def x "b")
(.replaceFirst (re-matcher #"." "a") x)
Reflection warning, /tmp/form-init17067666774915114420.clj:2:1 - call to method replaceFirst on java.util.regex.Matcher can't be resolved (argument types: unknown).
=> #'dev/x
=> "b"
Right, judging by the implementation of InstanceMethodExpr
, it'll start checking argument types only if there are more than 1 methods with the desired name and amount of arguments.
if you think there's a bug here, please report it on https://ask.clojure.org
How do I safely read a tagged literal with dots in it? e.g.:
(read-string "[1 2 3 (- 1 2) #foo.bar 1]")
=> throws ClassNotFound
And why the way to do it is an undocumented dynamic var? i.e.:
(binding [*suppress-read* true]
(read-string "[1 2 3 (- 1 2) #foo.bar 1]"))
=> [1 2 3 (- 1 2) #foo.bar 1]
is it safe to use?why do you have a tagged literal with dots in it?
the tag is read as a symbol and symbols with dots are assumed to be classes by various parts of the symbol resolvers
it would be better to use namespaces per normal symbol resolution - #foo/bar
class names are expected there for calling class constructors (per https://clojure.org/reference/reader#_deftype_defrecord_and_constructor_calls_version_1_3_and_later)
It's a problem with prepl where the remote process has a defrecord, so it serializes the record as a tagged map with dots, but the repl process does not have a record definition
well, it needs one
you're sending something on the wire the consumer needs to instantiate so it has to have that
there is no way to instantiate a record without having the record type
then the prepl server needs to print records in a way that can be read by any consumer (like as a map)
Generally I don't want my users to setup their prepl servers for Reveal to deserialize common data structures like records
To be fair, a record is not a “common data structure” - it’s a specific class whose definition must be evaluated to make instances
The common data structure version is a map with the same kv pairs as the record
It's not uncommon for Clojure users to use records, so I, as a tool author, would prefer that commonly used features work over prepl
they do ... if the client has the record definition
Yeah of course but swap in “classes” for “records” and it’s clear why this couldn’t work in Java proper, right?
prepl is print/read based. the prepl server needs to print things that clients can read
records (by default) print in a way that preserves type. types require type definitions to read.
so you either need to print in a way that does not require type, or provide the type on the client
Isn't the point of prepl that you can connect to a remote process that does not necessarily has the same setup and still work with it? E.g. what if a remote prepl process is cljs, while local is clj
I know I can instruct the prepl server to serialize records differently, I just don't want my users to have to do it for a tool to work
In that case, you still have to stick to the subset of types that both clojurescript and clojure can understand
Like you couldn’t send a JS object, right? You’d have to convert it to something the JVM side could read. Same problem with records thst are only present on one side
We are actually working on some stuff in this area that could help btw
Yeah, I can't send a JS object, and that's fine, a #js tagged literal is enough on the JVM side. Glad it's being worked on!
Is there some form that works like doseq, but steps over the binding in sync?
(frobsync [x [1 2 3 4]
y [1 2 3 4]]
[x y])
=> '([1 1] [2 2] [3 3] [4 4])