Fork me on GitHub
Jakub Holý (HolyJak)07:11:10

Hello! How is it possible that a nillable spec (v1) fails with NPE? This works just fine and as expected:

366   (s/def ::org-ds (s/nilable #(satisfies? % jdbc.p/Connectable)))
367   (s/conform ::org-ds nil) ;=> nil
but when I check specs using s/instrument s s/fdef then it fails in a test with NPE:
Caused by: java.lang.NullPointerException: null
 at clojure.core$instance_QMARK___5404.invokeStatic (core.clj:144)
    clojure.core$find_protocol_impl.invokeStatic (core_deftype.clj:536)
    clojure.core$satisfies_QMARK_.invokeStatic (core_deftype.clj:569)
    clojure.core$satisfies_QMARK_.invoke (core_deftype.clj:569)
    jakub.specs$fn__224908.invokeStatic (specs.clj:367)
    jakub.specs/fn (specs.clj:366)
    clojure.spec.alpha$spec_impl$reify__2059.conform_STAR_ (alpha.clj:923)
    clojure.spec.alpha$nilable_impl$reify__2556.conform_STAR_ (alpha.clj:1839)
    clojure.spec.alpha$conform.invokeStatic (alpha.clj:164)
    clojure.spec.alpha$deriv$fn__2425.invoke (alpha.clj:1537)
    clojure.spec.alpha$regex_spec_impl$reify__2509.conform_STAR_ (alpha.clj:1703)
    clojure.spec.test.alpha$spec_checking_fn$conform_BANG___3024.invoke (alpha.clj:121)
Why??? 🙏


Hmm, doesn't satisfies? take the protocol as the first argument?

Jakub Holý (HolyJak)10:11:37

Thank you! You were right, incorrect arg order t osatisfies? seems to have been the problem


in general, how flexible should specs be on the inputs that they accept / won't crash on. for example, in clojure.spec.alpha the kvs->map spec will crash if you pass it any non-collection:

=> (s/explain-data ::s/kvs->map [0])
=> (s/explain-data ::s/kvs->map 0)
#object[Error Error: 0 is not ISeqable]


using something such as: (s/and coll? ...) would avoid this problem


(for the definition of kvs->map)

Alex Miller (Clojure team)23:11:45

Well that function is essentially an internal spec to support s/keys* so it's only used in a coll context