Welcome! Please see the About page for a little more info on how this works.

+3 votes
in ClojureScript by

If you extend a type to implement a protocol, and then create an instance of that type that carries its own implementation of the same protocol in its metadata, ClojureScript will still use the implementation from the type, whereas Clojure uses the more specific metadata implementation.

Here's a brief example based on one of the tests for ClojureScript's protocol metadata implementation.

Edit: I am unable to make the code sample presentable in this editor, please see this gist instead: https://gist.github.com/cjohansen/a24257ecb5db15c7e20aaa25ff713b30

(defprotocol ExtMetaProtocol
:extend-via-metadata true
(ext-meta-protocol [x]))

(ext-meta-protocol (with-meta {} {`ext-meta-protocol (fn [_] 1)})) ;;=> 1

(extend-type clojure.lang.PersistentArrayMap
(ext-meta-protocol [m]


(ext-meta-protocol {}) ;;=> 2
(ext-meta-protocol (with-meta {} {`ext-meta-protocol (fn [_] 1)})) ;;=> cljs => 2, clj => 1

1 Answer

+3 votes

Confirmed that Clojure 1.10.1 and ClojureScript 1.10.520 behave differently from each other, in the way described in the sample REPL session. For cljs you must replace extend-type clojure.lang.PersistentArrayMap with extend-type cljs.core.PersistentArrayMap.

I would recommend going into the #cljs-dev channel of Clojurians Slack and pointing the ClojureScript developers at this issue to see if they are already aware of it or not.

I implemented the initial :extend-via-metadata support and can confirm that I implemented it based on the wrong assumptions (ie. actual impl is picked before meta).

The tests even reflect that assumption:
Do you know whether this is considered a bug in the JavaScript implementation, worth changing?
It should probably match the Clojure behavior yes.

It does hoewever mean that protocols using :extend-via-metadata will get "slower" overall since it cannot take the "shortcut" it currently takes.
I just hit this problem. Yet another subtle difference that makes writing portable code an issue.