Agreed; I was just following up on your previous comments.

But, it is useful to have something that can be used in a precondition and also 
shows an explanation.

I’m using, basically, (or (s/valid? spec x) (s/explain spec x)). It would be 
good to have this built-in too.

From: clojure@googlegroups.com [mailto:clojure@googlegroups.com] On Behalf Of 
Alex Miller
Sent: Wednesday, June 7, 2017 5:46 PM
To: Clojure <clojure@googlegroups.com>
Subject: Re: clojure.spec - Using :pre conditions (or not)?

Preconditions are already assertions, so it makes more sense to use s/assert in 
your code body than in a precondition.

On Wednesday, June 7, 2017 at 8:12:22 AM UTC-5, David Goldfarb wrote:
One big downside of using s/assert in a precondition:  It does not work with 
(s/nilable ...) specs, since s/assert returns valid values.

I fell into this trap for a moment of head-scratching just now.

On Wednesday, September 14, 2016 at 4:59:09 PM UTC+3, Alex Miller wrote:
Another option that has been added since the guide was written is s/assert 
which seems closer to what you're suggesting.

(defn name [user]
  {:pre [(s/assert :common/user user)]}
  (-> user :user/name))

;; need to enable assertion checking - this can also be enabled globally with 
system property clojure.spec.check-asserts
(s/check-asserts true)

(name {:user/name "Elon"})
"Elon"

(name {:x "Elon"})
ExceptionInfo Spec assertion failed
val: {:x "Elon"} fails predicate: (contains? % :user/name)
:clojure.spec/failure  :assertion-failed
  clojure.core/ex-info (core.clj:4725)

Rather than use it in a precondition, you can also use s/assert directly in the 
code.

On Wednesday, September 14, 2016 at 7:37:24 AM UTC-5, 
joakim.t...@nova.com<mailto:joakim.t...@nova.com> wrote:

(ns spec-test.core
  (:require [clojure.spec :as s]))

(s/def :user/name string?)
(s/def :common/user (s/keys :req [:user/name]))

; first version of name (using :pre)
(defn name [user]
  {:pre [(s/valid? :common/user user)]}
  (-> user :user/name))

; This statement works ok and returns "Elon":
(name {:user/name "Elon"})

; but this statement...
(name {:x "Elon"})

;...will throw:
CompilerException java.lang.AssertionError:
Assert failed: (s/valid? :common/user user)

; ...but then I don't get as much information
; about the error as if I would have called:
(s/explain :common/user {:x "Elon"})

;...which also contains the predicate:
val: {:x "Elon"} fails spec: :common/user
predicate: (contains? % :user/name)

; (second version of name - more verbose)
; or do I need to wite it like this:
(defn name [user]
  (let [parsed (s/conform :common/user user)]
    (if (= parsed ::s/invalid)
      (throw (ex-info "Invalid input" (s/explain-data :common/user user)))
      (-> user :user/name))))

; so that:
(name {:x "Elon"})

; ...will return:
CompilerException clojure.lang.ExceptionInfo:
  Invalid input #:clojure.spec{:problems}
    ({:path [], :pred (contains? % :user/name),
      :val {:x "Elon"}, :via [:common/user], :in []})

; It should be nice if I could be able to write it like this
; (or similar, to get a better error message):
(defn name [user]
  {:pre [(s/explain :common/user user)]}
  (-> user :user/name))
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to 
clojure@googlegroups.com<mailto:clojure@googlegroups.com>
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com<mailto:clojure+unsubscr...@googlegroups.com>
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google 
Groups "Clojure" group.
To unsubscribe from this topic, visit 
https://groups.google.com/d/topic/clojure/H9tk04sSTWE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to 
clojure+unsubscr...@googlegroups.com<mailto:clojure+unsubscr...@googlegroups.com>.
For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to