1

If you try to run the following code, you will see that it will compile, but fail at runtime on the second-to-last line due to "No protocol method NameSayer.say-name defined for type cljs.core/PersistentArrayMap: {}" even though it the satisfies? call returned true. A similar failure would occur for the IVector/PersistentVector case, despite also satisfying the required protocol.

(defprotocol NameSayer
  (say-name [input]))

(extend-protocol NameSayer
  number
  (say-name [_]
    "I'm a number!")

  string
  (say-name [_]
    "I'm a string!")

  IMap
  (say-name [_]
    "I'm a map!")

  IVector
  (say-name [_]
    "I'm a vector!"))

(println (satisfies? IMap {}))
(println (satisfies? IVector []))
(println (say-name "hello"))
(println (say-name 100))
(println (say-name {}]))
(println (say-name []))

I snooped around in clojurescript.core and saw that for something like IPrintWithWriter, implementations for PersistentArrayMap, PersistentHashMap, and PersistentTreeMap are simply duplicated despite all having the common IMap interface. Is there a better way to solve this than code duplication using protocols?

Amanda
  • 11
  • 2

1 Answers1

0

Some suggestions from a clojurians thread on the same topic:

If you control the protocol - take every method in the protocol and change it from method to method*

(defn method [o]
  (cond
    (satisfies? Proto o) 
    (method* o)

    (map? o)
    (map-impl o)

    (set? o)
    (set-impl o)

    (sequential? o)
    (sequential-impl o)

    :else
    (throw (ex-info "" {})))

you could also do via default if performance is not really much of a concern for your own protocols i.e. default + satisifes? etc.

Simon
  • 1