clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
Jakub Holý 2020-01-07T06:15:27.000100Z

Why not spec 2? Though not finished, I guess it bears completion (just the last 10% that use 90% of the time :rolling_on_the_floor_laughing:)...

telekid 2020-01-07T18:39:28.002300Z

I’ve got a spec(ish) design question that I’ve been thinking about for a while. I finally decided to throw it in a gist: https://gist.github.com/telekid/0f276bfa3b3f0d395a7a71158adbb35d I’m curious to know how other people approach this problem?

Eddie 2020-01-07T18:51:19.005600Z

@jake142 If ::animals/penguins is defined as a count (perhaps s/def ::penguins nat-int?) then I do not see a problem with reusing it. EDIT: Gist has been updated. Disregard! :)

telekid 2020-01-07T18:52:17.006200Z

Oh, I just realized that I made a typo

telekid 2020-01-07T18:52:22.006400Z

🤦

telekid 2020-01-07T18:52:24.006600Z

one moment

telekid 2020-01-07T18:52:52.006800Z

L20 how has ::animals/lions

Eddie 2020-01-07T18:54:37.007100Z

I see. Thanks for the clarification.

telekid 2020-01-07T19:05:23.008700Z

Sorry for the confusion!

vemv 2020-01-07T20:14:49.008900Z

In a given (ns models.geography.continent), I tend to solve this with:

(spec/def :models.geography.continent.penguins/animals ...)

(spec/def :models.geography.continent.lions/animals ...)
i.e. I don't use :: syntax for these cases, and I don't create additional Clojure namespaces (files). I call it the "synthetic ns pattern" It's a bit verbose, and losing the 1:1 mapping between cljs namespaces and spec namespaces isn't ideal either. But it's fairly occasional so I've been happy to use these for a couple years

vemv 2020-01-07T20:15:55.009100Z

btw, not sure if this solution is already described in your gist. sometimes I'm impatient 🙃

telekid 2020-01-07T20:48:57.009300Z

yeah, I like that

telekid 2020-01-07T20:49:26.009500Z

I’ve experimented with that a bit in a few places (but I forgot about it when I was writing the gist - thanks for bringing it up)

vemv 2020-01-07T20:56:32.009700Z

✌️! I realised, a more accurate nickname would be "synthetic sub-ns pattern". so, while it's not a 1:1 mapping, one is still reasonably close to that ideal

telekid 2020-01-07T21:08:51.009900Z

funnily enough, I’ve been using the same name: https://ask.clojure.org/index.php/2817/lighter-weight-aliasing-for-keywords?show=8918#a8918

😄 1
kenny 2020-01-07T21:37:10.011700Z

Why were multi-specs implemented using multi-methods? I have never found the dynamism of multimethods useful in defining multi-specs. In fact, I think I'd prefer all of the multi-spec types to be declared statically.

ghadi 2020-01-07T21:44:17.012600Z

@kenny so that they're open to extension

ghadi 2020-01-07T21:44:56.013500Z

in fact I can't think of anything in clojure that's closed

kenny 2020-01-07T21:45:11.013800Z

Right. At least interally, I've never found that useful. All type->keys are declared upfront. Multimethods make it hard to determine the input data.

ghadi 2020-01-07T21:45:55.014Z

> All type->keys are declared upfront. ?

kenny 2020-01-07T21:46:14.014300Z

Dispatch functions

ghadi 2020-01-07T21:47:44.015900Z

I'm sorry I still don't understand

kenny 2020-01-07T21:49:26.017200Z

For a particular entity, I know it has types A, B, C. It can never and should never be extended except directly in the definition.

kenny 2020-01-07T21:49:52.017800Z

All the variants of an entity are known upfront.

ghadi 2020-01-07T21:50:09.018500Z

ok that's your use case

Joe Lane 2020-01-07T21:50:12.018700Z

You might not be the one defining the multispecs, the users of your library may be.

💯 1
ghadi 2020-01-07T21:50:15.018800Z

^^

ghadi 2020-01-07T21:50:47.019900Z

and all the extensions in the extensions folder

kenny 2020-01-07T21:53:37.021400Z

Oh right, I see the use for libs. This internal use case is much different. Perhaps some sort of new macro is what we need:

(multi-spec2 {:type1 (s/keys :opt [])
              :type2 (s/keys :opt [])})

ghadi 2020-01-07T21:54:22.021900Z

wouldn't it be amazing if you can write that macro today?

1
😉 1
ghadi 2020-01-07T21:54:32.022300Z

😄

kenny 2020-01-07T22:32:49.023200Z

For those interested...

(defmacro closed-multi-spec
  [name dispatch-key dispatch->spec]
  (let [defmethods (map (fn [[dispatch spec-form]]
                          `(defmethod ~name ~dispatch
                             [~'_]
                             ~spec-form))
                        dispatch->spec)]
    `(do
       (defmulti ~name ~dispatch-key)
       ~@defmethods
       (s/multi-spec ~name ~dispatch-key))))
Don't know if this is where it'll land but it's a start.