-
Notifications
You must be signed in to change notification settings - Fork 257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Spec integration #366
Comments
FWIW I don't think Spec is a complete superset of Schema yet (e.g. completion) but it is close. The model for schema and spec is different enough (key registry, etc) that I think it could be nontrivial to use spec as a backend. And moreover (since part of the point of spec is to rally the community around a single way of writing schemas/specs), I'm not sure its a good idea to encourage people to write spec with an alternate syntax, especially one that doesn't necessary line up with its semantics (but thanks for your appreciation of Schema's syntax :)). We also want to keep compatibility with earlier Clojure versions for some amount of time, so couldn't replace the backend now regardless of the other points. If there was to be some connection between Schema and Spec, my initial thought (without having used spec yet myself) is that the most useful might be a 'Schema to Spec converter'; and a 'Schema with Spec Backend' as you suggest might be useful as a temporary shim (e.g. replacement library for schema) while refactoring from Schema to Spec or using third-party Schematized libraries with Spec. But, I think both of those would probably be separate projects from |
Thanks for the thoughtful response. The idea came from this discussion, and Alex Miller is actually supportive of a Schema to Spec converter. I definitely agree that it would be a non-trivial project however. In my view, Spec doesn't really make Schema obsolete as it's focus is more general. Schema provides a very intuitive way to describe data, and I think there's a lot of value in its syntax. Hopefully both will coexist in the future. :) |
Related: plumatic/plumbing#126. Will comment on that when out of the hammock ;) |
The map description in spec is more reusable than the one in schema. However, spec's s/cat etc is nice, but actually overkill if you have simple functions with fixed set of arguments. So, being able to write something like this would be really nice
where I just say that the function takes a ::foo and returns a ::foo |
My 2 cents:
We could host the ;; implicit schema fn-validation
(schema.core/defn foo :- Long [a :- Long] a)
;; explicit schema fn-validition
(schema.core/defn ^{:fn-validation :schema} foo :- Long [a :- Long] a)
;; adds :spec as valid fn-validation (mutable evil)
(require '[spec-tools.schema])
(clojure.spec.alpha/def ::id int?)
;; explicit spec fn-validation
(schema.core/defn ^{:fn-validation :spec} foo :- int? [a :- ::id] a)
;; override the default (mutable evil 2)
(defmethod schema.core/fn-validation :default [_] spec-tools.schema/SpecFNValidation)
;; implicit spec fn-validation
(schema.core/defn foo :- int? [a :- ::id] a) What do you think? btw, defining fns (and fnks) with spec works, they just don't implement (require '[clojure.spec.alpha :as s])
(s/def ::foo int?)
(schema.core/fn-schema
(schema.core/fn [a :- ::foo]))
; IllegalArgumentException No implementation of method: :explain of protocol: #'schema.core/Schema found for class: clojure.lang.Keyword clojure.core/-cache-protocol-fn (core_deftype.clj:583)
(schema.core/fn-schema
(schema.core/fn [a :- int?]))
; IllegalArgumentException No implementation of method: :explain of protocol: #'schema.core/Schema found for class: clojure.core$int_QMARK_ clojure.core/-cache-protocol-fn (core_deftype.clj:583)
(schema.core/fn-schema
(schema.core/fn [a :- (s/spec int?)]))
; IllegalArgumentException No implementation of method: :explain of protocol: #'schema.core/Schema found for class: clojure.spec.alpha$spec_impl$reify__751 clojure.core/-cache-protocol-fn (core_deftype.clj:583) I have a custom reader for fn-schema -> spec now in compojure-api. ;; schema
(POST "/plus" []
:query-params [b :- s/Int, {c :- s/Int 0}]
:body [numbers {:d s/Int}]
:return {:total s/Int}
(ok {:total (+ a b c (:d numbers))}))
;; (data-)specs
(POST "/plus" []
:query-params [b :- spec/int?, {c :- spec/int? 0}]
:body [numbers {:d spec/int?}]
:return {:total ::total}
(ok {:total (+ a b c (:d numbers))}) |
Thanks for the detailed proposal! To be up-front, I don't have the opportunity to do much Clojure these days, so any effort to add significant new functionality probably needs to be community-driven. As such, it might make sense to take this to the mailing list to see if others have thoughts. With that out of the way, can you say a little more about the goals of this effort? Do you just want a way to use specs with Schema s/defn syntax, or is there more to it than that? |
Thanks for the quick response. I would like to have same kind of boilerplate-free spec definitions for functions like Schema & Plumbing do for Schema. Many people have been talking about this in Slack etc. I guess there are 2 options:
|
Yeah, I guess my gut feeling is that if what you want is really another way to declare spec'd functions (without any use of the schema backend), that probably belongs in another library. I guess ideally that could be accomplished by splitting the schema syntax stuff into a separate library from the schema backend, but it sounds like neither of us have the bandwidth to tackle that. So back to reality, I guess I'm open to considering something like (1) so long as it doesn't interfere with the current applications or ergonomics of schema, someone else commits to test and maintain it, and it won't lead to a lot of rough edges for people that try to use it. (How will it play with the existing schema tools for coercion/generation, if at all, etc?). Another related question is whether you are hoping that under (1) spec-schema declarations will also work with plumbing and Honestly I think just copying schema and deleting everything that's not the syntax, then modifying from there seems like it might be the easiest approach. But if you really think (1) is the way to go I'm happy to keep talking things through. |
There is a Plumatic Schema (and plain clojure) syntax parser in malli nowadays: it doesn't care about the actual schema, just collects those. It emits malli schemas, but could be made configurable via a new If someone is interested in making a schema-spec-malli converter or one code: https://github.com/metosin/malli/blob/master/src/malli/destructure.cljc tests: https://github.com/metosin/malli/blob/master/test/malli/destructure_test.cljc |
Now that Spec is being added in Clojure 1.9, would it make sense for Schema to target it?
It seems like Spec is a superset of Schema functionality, but I think that Schema provides a much cleaner syntax for describing data. If Schema syntax would be used to generate Spec, then a lot of the complexity from the library could be offloaded to the standard Clojure library at that point.
The text was updated successfully, but these errors were encountered: