➜ clj
user=> (type ^{:type ::foo} [])
:user/foo
➜ cljs
cljs.user=> (type ^{:type ::foo} [])
cljs.core/PersistentVector
Seems ClojureScript's type
doesn't honor the :type
metadata the way that Clojure does.For comparison, Clojure
(defn class
"Returns the Class of x"
^Class [^Object x] (if (nil? x) x (. x (getClass))))
(defn type
"Returns the :type metadata of x, or its Class if none"
[x]
(or (get (meta x) :type) (class x)))
ClojureScript
(defn type
"Return x's constructor."
[x]
(when-not (nil? x)
(.-constructor x)))
So Clojure type
is really just class
but also checks (:type (meta ...))
. ClojureScript doesn't have class
.happy to make a ticket/patch, but would like confirmation that this is considered something that needs fixing. If so, should we do the same thing in cljs, i.e. rename type
to class
, and make type
check for meta then delegate to class
, or should cljs remain class
-less, and we only add the metadata check to type
this would be a breaking change - also hard to see the value of it
originally Rich left out type
, and I added it to be able to do some useful type based dispatch
usually alignment is good but I'm concerned that this one might have some repercussions - it would be interesting to know what use cases you have in mind
in Clojure I nearly always use type
the same way I use it in ClojureScript - I don't need the class bit (or the metadata stuff)
it's just to get host type distinction for dispatch
using :type
metadata can be quite convenient, for instance for multimethod dispatch, consider Clojure's own print-method
used by pr
and friends
(defmulti print-method (fn [x writer]
(let [t (get (meta x) :type)]
(if (keyword? t) t (class x)))))
which makes it easy to add specific dispatching for certain cases, for example Malli has a lot of reify
calls, so they all end up with a different class, but they all have the same :type
metadata https://github.com/metosin/malli/blob/master/src/malli/core.cljc#L95
print-method
is not a great example since we don't need that
clojure.pprint
on the other hand does not look at the :type
metadata, making it tricky to add dispatching for these types
what I mean is what can you not do w/ what you currently have
if you change type you change all uses of it
so anything thing that was flowing through will break if it happens to have the metadata
so the balance of "this is useful" / "this breaks stuff"
I can do everything fine, I can write my own type
that looks at (meta (:type))
, it's just an incosistency that seemed worth pointing out.
is not very compelling
I understand what you're saying - I'm justing saying type
is everywhere
and you're going to change it
yeah, fair enough, that does warrant careful consideration 🙂
I guess we're stuck with this one
I think when we have a better testing story it will be easier to make these kinds of decisions - but right now it's hard to know what will happen
I've been keeping some notes for an eventual "differences between clojure and clojurescript to watch out for" blog post, so this can go right onto the list