Fork me on GitHub
#clojure-spec
<
2018-09-07
>
bbrinck01:09:55

In clojure.spec.alpha “0.2.176”, is there a new way to install a custom printer for macro-expansion errors?

bbrinck01:09:07

It seems to work differently than in “0.2.168”, unless I’m missing something

bbrinck01:09:34

There may be some subtlety of https://dev.clojure.org/jira/browse/CLJ-2373 that I’m not understanding

seancorfield01:09:01

It's this patch https://dev.clojure.org/jira/secure/attachment/18391/clj-2373-spec-alpha-2.patch that removes the call to s/explain-out as part of simplifying the error messages.

seancorfield01:09:15

And specifically this part of the proposal: * stop printing data into message strings ExceptionInfo.toString should list keys, not entire map contents spec.alpha/macroexpand-check should stop including explain-out in message

seancorfield01:09:40

@bbrinck Interesting. I can reproduce the behavior in a Boot repl but if I use clj I get different behavior:

(! 504)-> clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.0-alpha7"}}}'
src/user.clj was loaded
Clojure 1.10.0-alpha7
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (set! s/*explain-out* (fn [ed] (println "failed")))
#object[user$eval5$fn__141 0x5b07730f "user$eval5$fn__141@5b07730f"]
user=> (let [x] 1)
Syntax error macroexpanding clojure.core/let at (3:1). Cause: Call to clojure.core/let did not conform to spec.
failed
user=> 

bbrinck02:09:02

@seancorfield Good to know - I am still using Clojure 1.9 in my repro. Maybe it’s an issue with using new clojure.spec without new clojure alpha?

seancorfield02:09:06

Compared to alpha 6

(! 505)-> clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.0-alpha6"}}}'
src/user.clj was loaded
Clojure 1.10.0-alpha6
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (set! s/*explain-out* (fn [ed] (println "failed")))
#object[user$eval5$fn__140 0x502f1f4c "user$eval5$fn__140@502f1f4c"]
user=> (let [x] 1)
CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
failed
 #:clojure.spec.alpha{:problems [{:path [:args :bindings :init-expr], :reason "Insufficient input", :pred clojure.core/any?, :val (), :via [:clojure.core.specs.alpha/bindings :clojure.core.specs.alpha/bindings], :in [0]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2499 0x5b07730f "clojure.spec.alpha$regex_spec_impl$reify__2499@5b07730f"], :value ([x] 1), :args ([x] 1)}, compiling:(NO_SOURCE_PATH:3:1) 
user=> 

bbrinck02:09:00

The announcement for spec.alpha 0.2.176 and core.specs.alpha 0.2.44 says “these libraries can be used now with Clojure 1.9.0”, so I expected that to work

seancorfield02:09:49

Confirmed, yes, the printing has changed:

(! 506)-> clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.9.0"} org.clojure/spec.alpha {:mvn/version "0.2.176"}}}'
src/user.clj was loaded
Clojure 1.9.0
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (set! s/*explain-out* (fn [ed] (println "failed")))
#object[user$eval15$fn__150 0x590c73d3 "user$eval15$fn__150@590c73d3"]
user=> (let [x] 1)
CompilerException clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec. #:clojure.spec.alpha{:problems [{:path [:bindings :init-expr], :reason "Insufficient input", :pred clojure.core/any?, :val (), :via [:clojure.core.specs.alpha/bindings :clojure.core.specs.alpha/bindings], :in [0]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2509 0x55b5f5d2 "clojure.spec.alpha$regex_spec_impl$reify__2509@55b5f5d2"], :value ([x] 1), :args ([x] 1)}, compiling:(NO_SOURCE_PATH:3:1) 
user=> 

bbrinck02:09:08

@seancorfield Thanks! Since it works in 1.10.0-alpha7, I may just add a note to Expound to suggest that people don’t upgrade to newest spec.alpha unless they also upgrade clojure. Or there may be a workaround

Alex Miller (Clojure team)02:09:01

I am too tired to grok the issue - can you recap?

seancorfield02:09:47

@alexmiller The change in 2373 that removes the explain-out call from several spec failures (and instead adds that call to the default REPL?) means that The details of the spec failure aren't run through a custom printer now in Clojure 1.9 or Boot REPL (and probably not in Leiningen's REPL -- I think both lein and boot use REPL-y?).

seancorfield02:09:49

(it's the right choice but it means that tools that print explain-data in fancy ways now need to hook into the REPL instead of expecting to be invoking in the spec failures themselves)

Alex Miller (Clojure team)03:09:55

It’s not that they aren’t run through a custom printer though, it’s that they’re not run through any printer, right?

Alex Miller (Clojure team)03:09:36

Previously they were printed into the exception message and now they’re not

Alex Miller (Clojure team)03:09:00

The hooking is still exactly the same, its just that repls need to be better about how they print. The 1.10 clojure.main has a new function exposed to help with this

4
seancorfield05:09:31

> It’s not that they aren’t run through a custom printer though, it’s that they’re not run through any printer, right? Yes, right. I could have worded that better 🙂

seancorfield05:09:30

> The hooking is still exactly the same, its just that repls need to be better about how they print. The 1.10 clojure.main has a new function exposed to help with this Boot and Leiningen have some work to do. Or REPL-y. 🙂

bbrinck14:09:08

@alexmiller I suspect I’ll get questions about this for Expound, so I’d like to put a notice for anyone who upgrades clojure.spec.alpha to “0.2.176”. What would you suggest? Should I recommend not upgrading to 0.2.176 unless they also upgrade to clojure 1.10.0-alpha7? Or until they upgrade to a newer version of Lein or Boot that changes the REPL printing?

bbrinck14:09:02

> The 1.10 clojure.main has a new function exposed to help with this which function is this? I’m toying around with a custom REPL built on top of rebel-readline

Alex Miller (Clojure team)14:09:53

that’s the function that builds the string to print in the repl

Alex Miller (Clojure team)14:09:47

for the note, I think the key is to just be clear about the combination of circumstances you’re warning about

Alex Miller (Clojure team)14:09:58

as those circumstances will change with subsequent releases of clojure, spec.alpha, and the tools involved

bbrinck16:09:40

thanks, i’ll add a warning to the readme

JH16:09:26

How would you spec this map?

dadair17:09:55

What do you want the spec to express? Have you read the spec guide? https://clojure.org/guides/spec

dadair17:09:19

“how would you spec this map” is very subjective; it depends on what you need. For example, a perfectly valid spec is (s/def ::map-thing map?), if that is a robust enough spec for your particular problem.

JH19:09:54

That makes sense, I just read through the guide and was able to figure it out. I wanted to spec that every key in the map was of certain type. Moreover that the :on-click was a function.