Fork me on GitHub

multi-spec dispatching on the first value in a sequence and returning the syntax for the rest of that sequence, possible at all ?


all examples of multi-specs i could find were about maps


what i'm trying to do : (s/def ::node (s/cat :tag keyword? (multispec dispatching on the tag here)))

Alex Miller (Clojure team)13:06:23

it is not only maps, can definitely be made to work with other things (I've got some stuff doing that)

Alex Miller (Clojure team)13:06:00

you can make your multimethod dispatch on first

Alex Miller (Clojure team)13:06:09

and then you have to be a little careful with the retag function

Alex Miller (Clojure team)13:06:23

I actually have an example of this in CLJ-2112 (specs on specs) I think

Alex Miller (Clojure team)13:06:24

you'll see spec-form is a defmulti on first

Alex Miller (Clojure team)13:06:59

and the ::spec spec uses (s/multi-spec spec-form (fn [val tag] val))

Alex Miller (Clojure team)13:06:26

and then the defmethods cover the different cases with different starting symbols


thanks looking at your example


ok got it working on the whole "sequence", i'm guessing this can't be done the way i want, dispatching on the first element in order to spec the rest of the sequence


not a huge deal, just a little usability issue i guess

Alex Miller (Clojure team)13:06:21

isn't the example above what you're describing?

Alex Miller (Clojure team)13:06:50

I'm using it to spec a form sequence based on the operator type at the beginning, so seems like the same thing?


(s/cat :tag keyword? :rest (s/multi-spec node-type :rest)) it looks like it's looking for a sequence in the rest


the mmultispec is returning something like (s/cat ....) a flat thing


is multispec like s/spec in this regard ?


(i have a hard time following your example)

Alex Miller (Clojure team)13:06:07

you don't want an s/cat here at all - the multi-spec is the sequence spec


but i need something to put around my stuff returned from the multimethod =)


but yes i understand

Alex Miller (Clojure team)13:06:03

I don't understand what that meant

Alex Miller (Clojure team)13:06:13

the multimethod returns the spec for the sequence


in the typical example for a typed map, you spec for the type keyword outside the multimethod


then only spec for what's relevant to the multispec user in the multimethod


but i think what i'm asking is impossible

Alex Miller (Clojure team)13:06:17

afaict what you're asking for is the example I gave. I don't get why it's not what you want.

Alex Miller (Clojure team)13:06:19

are you looking for something different in the conformed value shape?


in your example, i want the :f #{'clojure.core/fn} out of the multimethod


just like for the typical typed map examples


actually i'm wrong on that


event/type is indeed present in the multi-method in the guide


ok then sorry for the noise ><

Alex Miller (Clojure team)14:06:11

you can post-process the conformed value to do whatever you want of course


i was just weary that all the users of the multimethod will have to spec for the "tag"


not a huge deal since all those users are me =)


thanks for your time !

Alex Miller (Clojure team)14:06:40

yeah, you can just spec it as any? if you like

Alex Miller (Clojure team)14:06:58

it's already been chosen by the time you get into the multimethod and the value will flow through

Alex Miller (Clojure team)14:06:25

I spec'ed it in that code just for clarity

✔️ 4

When multi-specing where the specs are s/keys and the retag is a keyword, is it best practice to include the retag key as :req in the defmethods keys spec?

Alex Miller (Clojure team)17:06:11

not sure what you mean by "include the retag key as :req"

Alex Miller (Clojure team)17:06:45

oh, you mean as a :req in the s/keys

Alex Miller (Clojure team)17:06:20

well it is probably required to get to that point in the first place

Alex Miller (Clojure team)17:06:03

and either way it's going to end up in the conformed value

Alex Miller (Clojure team)17:06:50

I'm not sure that it matters either way, depends on whether you see the retag key as part of the data or as frame around the data, but that's probably dependent on your code


Ok cool, yeah I was doing it quite consistently in :req and ran into something where I was adding a :gen to the keys spec in the defmethod and found it a bit unergonomic to have to include the retag in the generator as well, which got me feeling like maybe it was better not to include it at all. I have been also specing the retag key mostly as something rather generic like keyword? too.