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

+1 vote
in Spec by

Spec {{instrument}} does not work on protocol methods. Invalid arguments will be accepted silently with no error. Protocol vars are included in the return value of {{(instrument)}}.

Steps to reproduce

'[clojure.spec :as s]
'[clojure.spec.test :as test])

(defprotocol P
(method [this arg]))

(defrecord R []
(method [this arg]

(str "R.method called with " (pr-str arg))))

(s/fdef method
:args (s/cat :this any?

           :arg number?))

(defn wrapped [this arg]
(method this arg))

(s/fdef wrapped
:args (s/cat :this any?

           :arg number?))


(println (method (->R) "not a number"))

(println (wrapped (->R) "not a number"))

This code produces the output:

R.method called with "not a number" clojure.lang.ExceptionInfo: Call to #'user/wrapped did not conform to spec: In: [1] val: "not a number" fails at: [:args :arg] predicate: number? ...

Possible resolutions

  1. Add support to {{instrument}} for protocol methods
  2. Document that {{instrument}} does not work on protocol methods, do not return protocol method Vars from {{(instrument)}}, throw exception if protocol method Vars are included in the symbols passed to {{(instrument syms)}}

See also

CLJ-1941 describes a different case where {{instrument}} does not work. This issue was identified in a (link: http://dev.clojure.org/jira/browse/CLJ-1941?focusedCommentId=43084&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-43084 text: comment).


This issue can be avoided by wrapping protocol methods in normal functions and spec'ing the functions. This is already common practice.

1 Answer

+1 vote
Reference: https://clojure.atlassian.net/browse/CLJ-2109 (reported by stuart.sierra)