I just discovered what I initially thought was a very useful (and of course scantily documented) feature of ClojureScript, namely the specify! macro. Now, immediately after my initial rejoicing, I further discovered that it didn’t work quite how I expected it to.
What I tried was the following:
(defprotocol Proto (do-stuff [this])) (let [v [ ] _ (specify! v Proto (say [this] :hello))] (say v))
So far so good, this is exactly what I’m after: the ability to extend a protocol over an instance of a type, record etc, rather than a given type, record.
This is great until I try to “change” the vector v using e.g. assoc, conj:
(let [v  _ (specify! v Proto (say [_] :hello)) v (conj v 1)] (say v))
which results in the error message:
#object[Error Error: No protocol method Proto.say defined for type cljs.core/PersistentVector: ]
Now, this does kind of sort of make sense to me, but I’m wondering, is this the expected behaviour? Or is this a bug which has been fixed in a subsequent version?
I’ve checked the documentation and the use cases seem to be limited to nil, any JS object, and the actual types, e.g. things defined by deftype, defrecord, rather than instances thereof.
If this is the correct behaviour, is there anything else which I can use to achieve the same outcome, that is, to be able to extend protocols over instances of types, records and so on? The reason I need to do this is that I want to be able to treat say a given map but not all maps as implementing xyz protocol.
The only other thing I can think of is to call specify! again after each modification, which is of course very clunky.