Placing this under the Beginners section because I’m completely new to spec.
What’s the difference between s/and & s/merge and when should I choose one over the other?
Placing this under the Beginners section because I’m completely new to spec.
What’s the difference between s/and & s/merge and when should I choose one over the other?
s/and will check that the map you have is a valid of both the map specs. Like it’ll check if it’s valid to the first spec, and if true, it’ll check if it’s also valid of the other spec. While s/merge will check that the map you have is valid to a union of their required and optional keys.
Since keys spec are open, I think when it comes to validating they’re pretty much the same. But when it comes to using the spec for generating sample maps that satisfy it, s/merge will be able to create a proper generator, while s/and might struggle and require you to provide a custom generator for it. So in general, I’d say use s/merge for maps, so anytime you have a s/and that is only anding map specs, prefer s/merge over it. Use s/and when one of the spec involved is not a map spec.
Another important difference is that with s/and, the conformed value from the first spec flows through the remaining predicates/specs. With s/merge the original value is used for each spec.
Thanks guys,
I’m working through the website material and am currently looking at this section: https://clojure.org/guides/spec#_a_game_of_cards
I wondered how I would use spec to catch cheaters in the model, so I came up with this:
(defn no-cheaters?
"Returns true if there are no duplicate cards in the game"
[{players ::players deck ::deck}]
(->
concat
(reduce deck (map ::hand players))
count (== 52)))
(s/def ::game
(s/and
no-cheaters?
(s/keys :req [::players ::deck])))
;; test
(s/explain ::game
{::deck (drop 2 deck)
::players [{::name "Kenny Rogers"
::score 100
::hand (take 2 deck)}]})
;; prints "Success!"
(s/explain ::game
{::deck (rest deck)
::players [{::name "Kenny Rogers"
::score 100
::hand (take 2 deck)}]})
;; .... - failed: no-cheaters? ...
This works with no-cheaters? as the first or second argument to s/and, but using s/merge instead does not work. Based on what you’ve told me I don’t understand why.
merge is for merging s/keys specs – it can’t be used with a predicate (like no-cheaters?). That’s what @didibus was saying about when to use s/and vs s/merge.
Ah, thanks for clearing that up! 
This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.