Search code examples
clojure

clojure.spec: `alt` vs `or` for sequence spec


I'm following clojure.spec's guide (http://clojure.org/guides/spec). I'm confused by the difference between alt and or for sequence spec.

For me the two following examples work equally well. So what's the difference between the two?

; Use `alt`
(s/def ::config (s/* (s/cat :prop string?
                        :val (s/alt :s string? :b boolean?))))
(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])

; Use `or`
(s/def ::config (s/* (s/cat :prop string?
                        :val (s/or :s string? :b boolean?))))
(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])

Solution

  • s/alt is for concatenating nested regex specs where using s/or specifies a nested sequence. In your example it doesn't make a difference since you are not using nested regex specs. Here is an example:

    (s/def ::number-regex (s/* number?))
    
    (s/def ::or-example (s/cat :nums (s/or :numbers ::number-regex)))
    
    (s/valid? ::or-example [1 2 3])
    ;;-> false
    (s/valid? ::or-example [[1 2 3]])
    ;;-> true
    

    As you can see, or specifies a nested sequence in which a new regex context is started, whereas alt specifies the opposite:

    (s/def ::alt-example (s/cat :nums (s/alt :numbers ::number-regex)))
    
    (s/valid? ::alt-example [1 2 3])
    ;;-> true
    (s/valid? ::alt-example [[1 2 3]])
    ;;-> false