ClojureScript

Port core.specs.alpha to ClojureScript

Details

  • Type: Enhancement Enhancement
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Completed
  • Affects Version/s: 1.9.908
  • Fix Version/s: None
  • Component/s: None
  • Labels:
  • Patch:
    Code
  • Approval:
    Accepted

Description

Port https://github.com/clojure/core.specs.alpha to ClojureScript, adding a cljs.core.specs.alpha namespace that has the specs in the Clojure version, modified as needed for ClojureScript. (We would ideally make minimal revisions, preserving as much original structure as reasonable, so that future upstream changes can be more easily ported. Additionally, tests should be ported over.)

The specs should be usable from both JVM-based and self-hosted ClojureScript. (This likely implies a design making clever use of cljc and reader-conditionals so that macro specs work for both ClojureScript variants.}

This would essentially be an experimental feature which, while shipping with ClojureScript, can be explicitly opted into by end-users who wish to make use of that namespace. In other words, it would not be required by any existing production code in the ClojureScript tree, at least initially. If it ships with ClojureScript, this can facilitate more broad experimentation and rooting out any fine tuning that may be needed in the specs.

We could add checks for the require and require-macros macros, heavily based on the support that exists in that namespace for the Clojure ns macro, but of course heavily modified to reflect ClojureScript's constraints and special features (string require, etc.)

We might also be able to use this work to to provide inspiration what to do about the subject of specing the ns special form. (Do we turn ns into a macro that expands to some other special form, or do we revise the compiler's macroexpand check to also be able to do special form checks?)

Activity

Hide
Thomas Heller added a comment -

FWIW I have been using some core.specs in shadow-cljs for a while now (just the JVM side though).

See:
https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/cljs/devtools/cljs_specs.clj

One major issue with these (or specs in general) is that the errors are absolutely terrible. Some checks done by the cljs.anaylzer or cljs.compiler provide far better error messages but don't test as strict. Lately I have been testing expound [1] which is a bit better but still far from good.

I'm also using spec to parse for the ns form which has the same issue but otherwise works very nice.
https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/build/ns_form.clj

[1] https://github.com/bhb/expound/

Show
Thomas Heller added a comment - FWIW I have been using some core.specs in shadow-cljs for a while now (just the JVM side though). See: https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/cljs/devtools/cljs_specs.clj One major issue with these (or specs in general) is that the errors are absolutely terrible. Some checks done by the cljs.anaylzer or cljs.compiler provide far better error messages but don't test as strict. Lately I have been testing expound [1] which is a bit better but still far from good. I'm also using spec to parse for the ns form which has the same issue but otherwise works very nice. https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/build/ns_form.clj [1] https://github.com/bhb/expound/
Hide
Mike Fikes added a comment -

The attached CLJS-2413-1.patch ports over the main namespace (there is no test namespace), making revisions for ClojureScript. Additionally, since we can't spec the ns special form, I added a few additional specs for require, require-macros, use, and use-macros.

Using the new namespace is easy: Just require cljs.core.specs.alpha and then specs will exist for:

cljs.core/defn
 cljs.core/defn-
 cljs.core/fn
 cljs.core/if-let
 cljs.core/import
 cljs.core/let
 cljs.core/require
 cljs.core/require-macros
 cljs.core/use
 cljs.core/use-macros
 cljs.core/when-let
Show
Mike Fikes added a comment - The attached CLJS-2413-1.patch ports over the main namespace (there is no test namespace), making revisions for ClojureScript. Additionally, since we can't spec the ns special form, I added a few additional specs for require, require-macros, use, and use-macros. Using the new namespace is easy: Just require cljs.core.specs.alpha and then specs will exist for:
cljs.core/defn
 cljs.core/defn-
 cljs.core/fn
 cljs.core/if-let
 cljs.core/import
 cljs.core/let
 cljs.core/require
 cljs.core/require-macros
 cljs.core/use
 cljs.core/use-macros
 cljs.core/when-let
Hide
Mike Fikes added a comment -

I tried some experiments with attaching a spec the ns special form:

Turning ns into a macro that expands to some other special form is challenging (I'm not convinced it is impossible, but you hit special circular cases when trying to bootstrap an environment this way). Perhaps this would be the "cleanest" solution, if it can be pulled off correctly.

Attempting to simply revise the macroexpand-check path to also work on special forms is problematic because you actually need a Var to attach a spec to.

The attached 0001-Experiment-Attach-ns-spec-to-internal-use-Var.patch, which applies after CLJS-2413-1.patch, illustrates a third potential approach: It introduces a internal-use macro Var to stand in for ns, attaches a spec to that internal-use Var, and then in the macroexpand-check path, special cases the ns special form to check any spec that might be attached to the internal-use Var.

With this experimental patch applied, you can indeed verify that ns forms can be spec-checked properly using the specs in that namespace.

Show
Mike Fikes added a comment - I tried some experiments with attaching a spec the ns special form: Turning ns into a macro that expands to some other special form is challenging (I'm not convinced it is impossible, but you hit special circular cases when trying to bootstrap an environment this way). Perhaps this would be the "cleanest" solution, if it can be pulled off correctly. Attempting to simply revise the macroexpand-check path to also work on special forms is problematic because you actually need a Var to attach a spec to. The attached 0001-Experiment-Attach-ns-spec-to-internal-use-Var.patch, which applies after CLJS-2413-1.patch, illustrates a third potential approach: It introduces a internal-use macro Var to stand in for ns, attaches a spec to that internal-use Var, and then in the macroexpand-check path, special cases the ns special form to check any spec that might be attached to the internal-use Var. With this experimental patch applied, you can indeed verify that ns forms can be spec-checked properly using the specs in that namespace.

People

Vote (2)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: