Fork me on GitHub
#clojure-spec
<
2016-09-11
>
ghufran00:09:37

I’m going through the spec tutorial on http://clojure.org . Is there any difference between using spec/or and using spec/alt ? It seems to work the same for the example from the tutorial: ` (s/def ::config-alt (s/* (s/cat :prop string? :val (s/alt :s string? :b boolean?)))) ;;=> :testspec.core/config-alt (s/conform ::config-alt [ "-server" "foo" "-verbose" true "-user" "joe"]) ;;=> [{:prop "-server", :val [:s "foo"]} {:prop "-verbose", :val [:b true]} {:prop "-user", :val [:s "joe"]}] (s/def ::config-or (s/* (s/cat :prop string? :val (s/or :s string? :b boolean?)))) ;;=> :testspec.core/config-or (s/conform ::config-or [ "-server" "foo" "-verbose" true "-user" "joe"]) ;;=> [{:prop "-server", :val [:s "foo"]} {:prop "-verbose", :val [:b true]} {:prop "-user", :val [:s "joe"]}]`

Alex Miller (Clojure team)00:09:16

Yes (although there are situations where they can yield the same result)

Alex Miller (Clojure team)00:09:02

in this particular example we are describing the structure of a sequential thing and regex ops are being used to specify that structure

Alex Miller (Clojure team)00:09:29

s/alt is the proper choice here as it is the regex op version

Alex Miller (Clojure team)00:09:06

it matters in the context where it is used - when used inside another regex op, it does not start a new nested context, rather it matches elements out of the current context

Alex Miller (Clojure team)00:09:23

however s/or is effectively opaquely matching a value

Alex Miller (Clojure team)00:09:42

so an example where alt works but or does not is:

Alex Miller (Clojure team)00:09:06

user=> (s/def ::a (s/alt :i int? :s (s/cat :a string? :b string?)))
:user/a
user=> (s/conform ::a [1])
[:i 1]
user=> (s/conform ::a ["a" "b"])
[:s {:a "a", :b "b”}]

Alex Miller (Clojure team)00:09:48

here an alt by itself implies a sequential context but that’s not true with s/or

Alex Miller (Clojure team)00:09:52

but the nested s/cat does (b/c also a regex op):

Alex Miller (Clojure team)00:09:56

user=> (s/def ::o (s/or :i int? :s (s/cat :a string? :b string?)))
:user/o
user=> (s/conform ::o 5)   ;; note 5 is a bare value, not in a collection
[:i 5]
user=> (s/conform ::o ["a" "b"])
[:s {:a "a", :b "b”}]

Alex Miller (Clojure team)00:09:22

and you can nest an alt inside another regex without requiring a new sequential context:

Alex Miller (Clojure team)00:09:25

user=> (s/conform (s/cat :k keyword? :nested-a ::a) [:foo 5])
{:k :foo, :nested-a [:i 5]}
user=> (s/conform (s/cat :k keyword? :nested-a ::a) [:foo "a" "b"])
{:k :foo, :nested-a [:s {:a "a", :b "b"}]}

Alex Miller (Clojure team)00:09:43

here ::a is embedded inside something else but just describes more elements of the sequence

ghufran01:09:41

Thanks @alexmiller! The guide to spec is great so far, will keep working through it!