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

0 votes
in Spec by

user> (require '[clojure.spec :as s])
user> (defrecord Box [a])
user> (s/conform

    (s/cat :boxes (s/* #(instance? Box %))
           :name (s/coll-of integer?))
    [(Box. 0) [5]])

UnsupportedOperationException Can't create empty: user.Box user.Box (form-init8049111656025227309.clj:1)
user> (clojure.repl/pst *e)
UnsupportedOperationException Can't create empty: user.Box

   	user.Box (NO_SOURCE_FILE:2)
clojure.core/empty (core.clj:5151)
clojure.spec/every-impl/cfns--14008/fn--14014 (spec.clj:1215)
clojure.spec/every-impl/reify--14027 (spec.clj:1229)
clojure.spec/conform (spec.clj:150)
clojure.spec/dt (spec.clj:731)
clojure.spec/dt (spec.clj:727)
clojure.spec/deriv (spec.clj:1456)
clojure.spec/deriv (spec.clj:1463)
clojure.spec/deriv (spec.clj:1467)
clojure.spec/re-conform (spec.clj:1589)
clojure.spec/regex-spec-impl/reify--14267 (spec.clj:1633)


This is a regression from -alpha7; the same sort of spec (modulo the default-value arg to coll-of) works as expected there.

4 Answers

0 votes
_Comment made by: alexmiller_

In this case, it's considering the s/* to be a non-match and then matching the (Box. 0) against (s/coll-of integer?). This matches the initial predicate (coll?) but falls through to the :else case which presumes it can call `empty`.

You can work around it by adding a :kind predicate to the coll-of:

        (s/cat :boxes (s/* #(instance? Box %))
               :name (s/coll-of integer? :kind #(not (record? %))))
        [(Box. 0) [5]])
;;=> {:boxes [#user.Box{:a 0}], :name [5]}
0 votes

Comment made by: interstar

But why does it need to do empty in the first place?

Does this mean that you can't check collections of records in spec?

0 votes

Comment made by: oakes

I ran into this myself. Conforming a record to a coll-of spec should show a normal spec error, not throw from deep inside spec's implementation.

0 votes
Reference: https://clojure.atlassian.net/browse/CLJ-1975 (reported by cemerick)