One way to prevent that would be to only ever use aliases for fully qualified keywords, never type out the whole thing.
On Thursday, November 9, 2017 at 11:22:24 PM UTC-8, Didier wrote: > > I just stumbled upon another potential mistake here. When you have specs > split across namespaces. Its possible for a map spec in one namespace to > have one of its key's use a spec from another namespace. If you forget to > require that other namespace though, you won't know, and your map will > always validate. > > (s/def ::spec (s/keys :req [:other/spec])) > > If :other/spec is not registered, ::spec still will succeed at being > registered. And then, assuming :other/spec is defined as: > > (s/def :other/spec int?) > > I wouldn't matter, since: > > (s/valid? ::spec {:other/spec "123"}) > > Will return true. > > But if you register :other/spec, it would return false. > > Normally, this has not been an issue for me, but now that I share my specs > more, I've got specs in different namespace using one another, and I've > already made this mistakes a few time, causing validation I thought was > there to protect me, to actually be missing. > > So I made my own keys macro: > > (defmacro known-keys > [& {:keys [req req-un opt opt-un gen] :as args}] > (letfn [(known-spec? [k] (boolean (s/get-spec k)))] > (doseq [e (concat req req-un opt opt-un)] > (when (not (known-spec? e)) > (throw (ex-info (str e " is not a currently registered spec.") > args))))) > `(s/keys ~@(interleave (keys args) (vals args)))) > > Which first checks that all keys are currently registered, and if so, it > delegates back to s/keys. Otherwise it throws an exception at macro > expansion time. > > I think this would also solve OPs problem, since it would throw if typos > are made also. > > On Saturday, 14 October 2017 04:45:47 UTC-7, stuart....@gmail.com wrote: >> >> Hi Leon, >> >> I think it would be a mistake to introduce temporal coupling to prevent >> typos. Here is an alternative that lets you identify "missing" keys specs at >> the time and place of your choosing, and then handle them as you deem >> appropriate, without imposing those decisions on other users of spec: >> >> https://gist.github.com/stuarthalloway/f4c4297d344651c99827769e1c3d34e9 >> >> Regards, >> Stu >> >> >> >> >> On Tue, Oct 10, 2017 at 12:33 PM, Leon Grapenthin <grapent...@gmail.com> >> wrote: >> >>> In terms of code loading, acyclic dependencies turned out to be a great >>> design choice in Clojure - why its benefits shouldn't apply to or be >>> justified for spec loading is totally unclear to me. >>> >>> To make my point more clear let me recap. I am simply asking for s/keys >>> to throw if provided specs aren't registered. Because my colleagues and I >>> myself made costly mistakes that would have been prevented. The most common >>> scenario is a typo like the one I have illustrated above. >>> >>> I have asked what benefits justify current behavior? >>> >>> The only justification comes from Sean saying that it helps him >>> prototyping. While I agree I also observe that this is simultaneously the >>> trapdoor leading to such silently passing specs. And why prototyping needs >>> should not be a primary concern in how s/keys behaves. >>> >>> I have tried to make a case for current behavior: It allows to say a key >>> is there, without saying anything about its value. I have pointed out (s. >>> a.) why this IMO has too little utility to justify anything. >>> >>> Regarding Clojure being a dynamic lanugage this doesn't really make a >>> difference here: There is not much dynamic going on about registration and >>> spec in general. Registration etc. is evaluated at compile time. Note that >>> s/def, s/keys etc. are all macros whose expansion is evaluated at compile >>> time. >>> >>> On Monday, October 9, 2017 at 7:20:42 PM UTC+2, Beau Fabry wrote: >>>> >>>> > The argument that existence of specs provided to s/keys can only be >>>> checked at runtime is false. >>>> >>>> > The argument that that recursive specs are impossible if existence of >>>> specs provided to s/keys was checked at compile time is also false. >>>> >>>> Could you explain to us why this is false? Clojure is a dynamic >>>> language, as such I don't see how you could define a time when all specs >>>> need to be present. How would I enter this spec at the repl if spec >>>> definition was required at s/keys invocation time? >>>> >>> >>> >>>> >>>> On Friday, October 6, 2017 at 4:32:41 PM UTC-7, Leon Grapenthin wrote: >>>>> >>>>> The argument that existence of specs provided to s/keys can only be >>>>> checked at runtime is false. >>>>> >>>>> The argument that that recursive specs are impossible if existence of >>>>> specs provided to s/keys was checked at compile time is also false. >>>>> >>>>> The usecase for libraries is not convincing: If the libraries author >>>>> states "the map has to have a key K" nobody can spec K further since that >>>>> would be a race condition among consumers (who s/defs K first?). >>>>> Requiring >>>>> the libraries author to declare K as any? would at least require him to >>>>> decide and convey his intent. >>>>> >>>>> The argument that not checking a value associated with a key is >>>>> corresponding to a guding design principle of map specs being based on a >>>>> keyset is not stating enough to justify discussed behavior. The utility >>>>> of >>>>> knowing that a keyset is present is close to none, which should be the >>>>> main >>>>> reasons why s/keys validates values. Again: Saying "A map that has a key >>>>> called ::foo" is pretty pointless in Clojure. If every map in every >>>>> Clojure >>>>> program I wrote had a key ::foo they would all produce the exact same >>>>> results as if they didn't and I bet yours would, too. >>>>> >>>>> Prototyping is indeed a bit more easy if one does not have to to >>>>> declare every spec used in a s/keys. However, that is particularly >>>>> damning >>>>> if you forget to add that spec later or mistype its name when doing so. >>>>> Which happens, and which is why I'm unhappy with this design letting such >>>>> typical human errors pass compilation. It would also help my prototyping >>>>> needs if I could reference symbols that are not declared, but I prefer >>>>> the >>>>> compiler errors before going live. >>>>> >>>>> On Saturday, October 7, 2017 at 12:01:34 AM UTC+2, Sean Corfield wrote: >>>>>> >>>>>> As one of the (apparently pretty uncommon) users who actually does >>>>>> happily define s/keys specs without correspondingly speccing the leaves >>>>>> as >>>>>> an "incrementally lock down/validate" approach, I wouldn't be too upset >>>>>> if >>>>>> I lost that ability and it started throwing an error. I mean it throws >>>>>> an >>>>>> error if I go to generate it anyway. >>>>>> >>>>>> >>>>>> >>>>>> **puts hand up!** >>>>>> >>>>>> >>>>>> >>>>>> I don’t want to have to write (s/def ::some-key any?) all over the >>>>>> place as I’m developing specs, just to satisfy an overly eager checker >>>>>> (in >>>>>> my mind). Worse, since the check would need to be deferred until >>>>>> validation >>>>>> time, as Beau notes, the omission of an “any?” key spec might not even >>>>>> show >>>>>> up until much further down the line. >>>>>> >>>>>> >>>>>> >>>>>> To me, this default behavior of silently not checking the _*value*_ >>>>>> associated with a _*key*_ is in keeping with the design principles >>>>>> of spec which focus on maps being based on a *key set*, while >>>>>> offering functions to allow you to optionally check values. >>>>>> >>>>>> >>>>>> >>>>>> Sean Corfield -- (970) FOR-SEAN -- (904) 302-SEAN >>>>>> An Architect's View -- http://corfield.org/ >>>>>> >>>>>> "If you're not annoying somebody, you're not really alive." >>>>>> -- Margaret Atwood >>>>>> >>>>>> >>>>>> ------------------------------ >>>>>> *From:* clo...@googlegroups.com <clo...@googlegroups.com> on behalf >>>>>> of Beau Fabry <imf...@gmail.com> >>>>>> *Sent:* Friday, October 6, 2017 9:10:36 AM >>>>>> *To:* Clojure >>>>>> *Subject:* Re: [core.spec] Stricter map validations? >>>>>> >>>>>> A use case that comes to mind is a system/library that specifies the >>>>>> structure of some inputs/outputs, but lets users/consumers (optionally) >>>>>> specify further validation of the leaves. I suppose that would be >>>>>> possible >>>>>> with (s/def ::foo any?) but you'd have to be a bit more careful about >>>>>> load >>>>>> order. The other use case (which is mine) is I'm just lazy and only want >>>>>> to >>>>>> write out broad strokes specs sometimes without getting into the nitty >>>>>> gritty. >>>>>> >>>>>> If s/keys were to validate that the keys it's provided have specs it >>>>>> would have to do it at validation time, so you wouldn't get the error >>>>>> until >>>>>> something was actually validated against that key spec. Trying to do it >>>>>> at >>>>>> definition time would break recursive specs. >>>>>> >>>>>> As one of the (apparently pretty uncommon) users who actually does >>>>>> happily define s/keys specs without correspondingly speccing the leaves >>>>>> as >>>>>> an "incrementally lock down/validate" approach, I wouldn't be too upset >>>>>> if >>>>>> I lost that ability and it started throwing an error. I mean it throws >>>>>> an >>>>>> error if I go to generate it anyway. >>>>>> >>>>>> On Friday, October 6, 2017 at 8:58:38 AM UTC-7, Leon Grapenthin >>>>>> wrote: >>>>>>> >>>>>>> Thanks, Beau. >>>>>>> >>>>>>> I am still interested why this default behavior has been chosen. It >>>>>>> doesn't seem like a reasonable trade-off at this point. >>>>>>> >>>>>>> It enables me to say: "The map must have this key", without >>>>>>> specifying how the data mapped to it will look like. >>>>>>> >>>>>>> If I ever wanted to do that, I could as well spec that key with >>>>>>> "any?". >>>>>>> >>>>>>> What are other benefits? They must justify the expense of likely >>>>>>> runtime errors. >>>>>>> >>>>>>> >>>>>>> On Friday, October 6, 2017 at 5:34:16 PM UTC+2, Beau Fabry wrote: >>>>>>>> >>>>>>>> Leon, perhaps you could add this code to your test suite? >>>>>>>> >>>>>>>> boot.user=> (let [kws (atom #{})] >>>>>>>> #_=> (clojure.walk/postwalk (fn [x] (when >>>>>>>> (qualified-keyword? x) (swap! kws conj x)) x) (map s/form (vals >>>>>>>> (s/registry)))) (clojure.set/difference @kws (set (keys (s/registry)))) >>>>>>>> #_=> ) >>>>>>>> #{:clojure.spec.alpha/v :clojure.spec.alpha/k} >>>>>>>> boot.user=> >>>>>>>> >>>>>>>> On Friday, October 6, 2017 at 5:56:29 AM UTC-7, Leon Grapenthin >>>>>>>> wrote: >>>>>>>>> >>>>>>>>> Open maps/specs are fine. >>>>>>>>> >>>>>>>>> s/keys supporting unregistered specs are not. >>>>>>>>> >>>>>>>>> At least to me. I just fixed two more bugs in production that were >>>>>>>>> would not have happened. >>>>>>>>> >>>>>>>>> What are the supposed benefits of this feature? >>>>>>>>> >>>>>>>>> I can only infer "being able to require keys without their spec >>>>>>>>> being known" which is a usecase I had exactly 0.00% of the time so >>>>>>>>> far. >>>>>>>>> >>>>>>>>> Anything I have missed? >>>>>>>>> >>>>>>>>> Kind regards, >>>>>>>>> Leon. >>>>>>>>> >>>>>>>>> >>>>>>>>> On Wednesday, October 4, 2017 at 7:05:29 PM UTC+2, Beau Fabry >>>>>>>>> wrote: >>>>>>>>>> >>>>>>>>>> Seems like that's the reasonable place to check it, otherwise >>>>>>>>>> you're forced into an ordering for your specs and cannot write >>>>>>>>>> recursive >>>>>>>>>> strict map specs. >>>>>>>>>> >>>>>>>>>> On Wednesday, October 4, 2017 at 8:59:59 AM UTC-7, Yuri >>>>>>>>>> Govorushchenko wrote: >>>>>>>>>>> >>>>>>>>>>> Thanks. This approach is also different from the macro because >>>>>>>>>>> it will check specs existence at the validation time, not at the >>>>>>>>>>> s/def call. >>>>>>>>>>> >>>>>>>>>>> On Wednesday, October 4, 2017 at 4:18:16 PM UTC+3, Moritz Ulrich >>>>>>>>>>> wrote: >>>>>>>>>>>> >>>>>>>>>>>> Yuri Govorushchenko <yuri....@gmail.com> writes: >>>>>>>>>>>> >>>>>>>>>>>> > Thank you the pointers! So far I ended up with writing a >>>>>>>>>>>> small `map` macro >>>>>>>>>>>> > which is similar to `s/keys` but checks that keys are already >>>>>>>>>>>> in the >>>>>>>>>>>> > registry: >>>>>>>>>>>> https://gist.github.com/metametadata/5f600e20e0e9b0ce6bce146c6db429e2 >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> Note that you can simply combine a custom predicate and >>>>>>>>>>>> `s/keys` in >>>>>>>>>>>> clojure.spec to verify that all keys in a given map have a >>>>>>>>>>>> underlying >>>>>>>>>>>> spec: >>>>>>>>>>>> >>>>>>>>>>>> ``` >>>>>>>>>>>> (s/def ::whatever (s/and (s/keys ...) >>>>>>>>>>>> #(every? keyword? (keys %)) >>>>>>>>>>>> #(every? (comp boolean s/get-spec) >>>>>>>>>>>> (keys %)) ) >>>>>>>>>>>> ``` >>>>>>>>>>>> >>>>>>>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "Clojure" group. >>>>>> To post to this group, send email to clo...@googlegroups.com >>>>>> Note that posts from new members are moderated - please be patient >>>>>> with your first post. >>>>>> To unsubscribe from this group, send email to >>>>>> clojure+u...@googlegroups.com >>>>>> For more options, visit this group at >>>>>> http://groups.google.com/group/clojure?hl=en >>>>>> --- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "Clojure" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>> send an email to clojure+u...@googlegroups.com. >>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>> >>>>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To post to this group, send email to clo...@googlegroups.com >>> Note that posts from new members are moderated - please be patient with >>> your first post. >>> To unsubscribe from this group, send email to >>> clojure+u...@googlegroups.com >>> For more options, visit this group at >>> http://groups.google.com/group/clojure?hl=en >>> --- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to clojure+u...@googlegroups.com. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.