# ClojureScript specify! macro

**URL:** https://clojureverse.org/t/clojurescript-specify-macro/6134
**Category:** Troubleshooting
**Tags:** clojurescript
**Created:** [June 19, 2020, 12:19pm UTC](https://clojureverse.org/t/clojurescript-specify-macro/6134 "2020-06-19T12:19:29Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![outrovurt](https://clojureverse.org/letter_avatar_proxy/v4/letter/o/f08c70/32.png) [@outrovurt](https://clojureverse.org/u/outrovurt)
#### Post date: [June 19, 2020, 12:19pm UTC](https://clojureverse.org/t/clojurescript-specify-macro/6134/1 "2020-06-19T12:19:30Z")

</div>

Hi,

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))

```

which returns:

`:hello`

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: [1]]`

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.

Thanks!  
Ali

---

<div class="post-metadata">

### Author: ![thheller](https://clojureverse.org/user_avatar/clojureverse.org/thheller/32/534_2.png) [@thheller](https://clojureverse.org/u/thheller)
#### Post date: [June 19, 2020, 3:28pm UTC](https://clojureverse.org/t/clojurescript-specify-macro/6134/2 "2020-06-19T15:28:07Z")

</div>

> [@outrovurt](#):
>
> is this the expected behaviour?

Yes. Remember when you call `conj` that you get a new instance of a vector back. It does not modify the first one which had the Proto impl. The specify! is not copied over as that wouldn’t make sense.

What you can do is use the `:extend-via-metadata true` setting in the protocol and add the impl via metadata.

```auto
(defprotocol Proto
  :extend-via-metadata true
  (say [this]))

(let [v (with-meta [] {`say (fn [this] :hello)})
      w (conj v 1)]
  (prn (say v))
  (prn (say w)))

```

---

<div class="post-metadata">

### Author: ![outrovurt](https://clojureverse.org/letter_avatar_proxy/v4/letter/o/f08c70/32.png) [@outrovurt](https://clojureverse.org/u/outrovurt)
#### Post date: [June 20, 2020, 2:37am UTC](https://clojureverse.org/t/clojurescript-specify-macro/6134/3 "2020-06-20T02:37:26Z")

</div>

Yes, your explanation does indeed make perfect sense, I thought it might be something like that.

I had absolutely no idea about `:extend-via-metadata true`, that is a really useful thing to know, and thank you for providing it.

p.s. Off-topic: how do you get syntax highlighting for your code?

---

<div class="post-metadata">

### Author: ![seancorfield](https://clojureverse.org/user_avatar/clojureverse.org/seancorfield/32/195_2.png) [@seancorfield](https://clojureverse.org/u/seancorfield)
#### Post date: [June 20, 2020, 4:10am UTC](https://clojureverse.org/t/clojurescript-specify-macro/6134/4 "2020-06-20T04:10:33Z")

</div>

> [@outrovurt](#):
>
> Off-topic: how do you get syntax highlighting for your code?

Like this:

````
```clojure
```

````

---

<div class="post-metadata">

### Author: ![outrovurt](https://clojureverse.org/letter_avatar_proxy/v4/letter/o/f08c70/32.png) [@outrovurt](https://clojureverse.org/u/outrovurt)
#### Post date: [June 20, 2020, 5:10am UTC](https://clojureverse.org/t/clojurescript-specify-macro/6134/5 "2020-06-20T05:10:43Z")

</div>

Aha! Thanks .

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [December 19, 2020, 5:10pm UTC](https://clojureverse.org/t/clojurescript-specify-macro/6134/6 "2020-12-19T17:10:45Z")

</div>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.
