expound

william 2021-01-09T16:10:30.102400Z

hey! I'm unsure on how to integrate expound in a cljs project: I added [expound "0.8.7"] to my shadow-cljs.edn, and then I changed the init! function to:

(defn ^:export init! []
  (set! s/*explain-out* expound/printer)
  (mount-root))
that said, when a spec fails, I still get the usual error in the emacs minibuffer. No expound magic! Can you help me?

bbrinck 2021-01-09T17:02:22.104Z

@meditans Is it possible to test this without emacs? Does this reproduce if you just call the function in a shadow-cljs REPL on the command line?

bbrinck 2021-01-09T17:02:52.104800Z

(I haven’t used shadow-cljs, so I’m not familiar with the tooling)

william 2021-01-09T17:04:03.106700Z

ok, so, the library works if I do something like (expound/expound string? 1)

bbrinck 2021-01-09T17:04:25.107700Z

What if you instrument a function and then call it with invalid parameters?

william 2021-01-09T17:04:35.108200Z

it prints the output that I would expect; it's just that I don't know what to do to make my program aware

bbrinck 2021-01-09T17:04:36.108500Z

(In the command-line REPL)

william 2021-01-09T17:04:43.108700Z

let's see

bbrinck 2021-01-09T17:06:27.111100Z

In particular, CIDER can do several things with errors - it can print them to the REPL in emacs, or it can open up a CIDER specific error buffer. It should be possible to see Expound errors in the former, but I don’t know how to adjust the latter.

bbrinck 2021-01-09T17:07:15.112400Z

That’s because the code in your REPL doesn’t impact how CIDER prints spec errors - that’s specific to CIDER itself, which doesn’t know about expound

william 2021-01-09T17:12:32.114100Z

give me a couple of minutes, I'm still learning clojure and I'm unsure on how to do a couple of things; googling

1👍
bbrinck 2021-01-09T17:17:10.117500Z

No rush. My reason I’m asking these questions 1. A command-line REPL is simplest. This will prove we are actually getting everything set up correct e.g. init! is being called as expected 2. If that works, we can then connect to a REPL in CIDER and try typing everything out in REPL, see if that works 3. Finally we can try evaluating commands in CIDER within the actual code buffer, and see what happens.

william 2021-01-09T17:17:47.118100Z

ok here's what I did:

(defn add1 [x] (+ 1 x))
(s/fdef add1 :args number?)
(stest/instrument `add1)

;; now (add1 nil) gives the normal error

(set! s/*explain-out* expound/printer)

;; (add1 nil) gives still the normal error

william 2021-01-09T17:18:30.118800Z

ok, that was done in a repl emacs opened for me. Is there a preferred way of calling a plain repl?

bbrinck 2021-01-09T17:24:12.119500Z

Where is the normal error printed? In the REPL buffer?

william 2021-01-09T17:24:23.120Z

indeed

william 2021-01-09T17:26:02.121700Z

that buffer is called cider-repl clojure/...

bbrinck 2021-01-09T17:26:29.122200Z

Interesting! Here’s the same repro in a basic terminal REPL started with clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.773"} expound {:mvn/version "0.8.7"}}}' -e cljs.main -re node

(require '[clojure.spec.test.alpha :as stest])
(require '[clojure.spec.alpha :as s])
(require '[expound.alpha :as expound])

(defn add1 [x] (+ 1 x))
(s/fdef add1 :args number?)
(stest/instrument `add1)
(set! s/*explain-out* expound/printer)
(add1 nil)

william 2021-01-09T17:26:43.122500Z

thank you let me try that

bbrinck 2021-01-09T17:26:47.122700Z

That prints:

Execution error - invalid arguments to cljs.user/add1 at (<cljs repl>:1).
<filename missing>:<line number missing>

-- Spec failed --------------------

Function arguments

  (nil)

should satisfy

  number?

-------------------------
Detected 1 error

bbrinck 2021-01-09T17:27:36.123900Z

which leads me to believe the next step is trying to figure out a CLJS REPL in shadow and see if it’s different (my REPL above is not managed by shadow, just so we can compare)

william 2021-01-09T17:27:46.124200Z

hmm here's what I get:

clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.773"} expound {:mvn/version "0.8.7"}}}' -e cljs.main -re node
DEPRECATED: Libs must be qualified, change expound => expound/expound 
WARNING: When invoking clojure.main, use -M
Syntax error (ClassNotFoundException) compiling at (REPL:0:0).
cljs.main

Full report at:
/tmp/clojure-485995736718039585.edn

bbrinck 2021-01-09T17:28:08.124500Z

ah, sorry, my CLJ is probably a bit old.

bbrinck 2021-01-09T17:28:22.124800Z

clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.773"} expound/expound {:mvn/version "0.8.7"}}}' -e cljs.main -re node

bbrinck 2021-01-09T17:28:27.125Z

does that work?

william 2021-01-09T17:29:08.125500Z

no, but a somehow smaller message:

WARNING: When invoking clojure.main, use -M
Syntax error (ClassNotFoundException) compiling at (REPL:0:0).
cljs.main

Full report at:
/tmp/clojure-3622056146492718952.edn

william 2021-01-09T17:29:23.125800Z

so no deprecation, and no warning

bbrinck 2021-01-09T17:30:48.126400Z

Well shoot. Let me upgrade my version of clj

bbrinck 2021-01-09T17:31:04.126800Z

clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.773"} expound {:mvn/version "0.8.7"}}}' -M -m cljs.main -re node might work, but upgrading is taking a second

william 2021-01-09T17:31:35.127Z

yeah, that works

william 2021-01-09T17:31:48.127400Z

is the only difference expound vs expound/expound?

bbrinck 2021-01-09T17:31:56.127600Z

and I added “-M”

william 2021-01-09T17:32:39.128Z

I see, to "supply main opts" I imagine

william 2021-01-09T17:32:45.128200Z

let me complete the test

william 2021-01-09T17:34:01.128600Z

yes that prints everything in the format expected by expound

william 2021-01-09T17:34:14.129100Z

ClojureScript 1.10.773
cljs.user=> (require '[clojure.spec.test.alpha :as stest])
nil
cljs.user=> (require '[clojure.spec.alpha :as s])
nil
cljs.user=> (require '[expound.alpha :as expound])
nil
cljs.user=> (defn add1 [x] (+ 1 x))
#'cljs.user/add1
cljs.user=> (s/fdef add1 :args number?)
cljs.user/add1
cljs.user=> (stest/instrument `add1)
[cljs.user/add1]
cljs.user=> (set! s/*explain-out* expound/printer)
#object[expound$alpha$printer]
cljs.user=> (add1 nil)
Execution error - invalid arguments to cljs.user/add1 at (<cljs repl>:1).
<filename missing>:<line number missing>

-- Spec failed --------------------

Function arguments

  (nil)

should satisfy

  number?

-------------------------
Detected 1 error

bbrinck 2021-01-09T17:34:30.129500Z

Hm, so I think the next question is “does it work with shadow-cljs without emacs?”

william 2021-01-09T17:34:54.130300Z

which means, how do I open a shadow repl? Let me try googling

bbrinck 2021-01-09T17:35:03.130500Z

It looks like shadow can start a REPL with shadow-cljs cljs-repl app or shadow-cljs node-repl but I’m going to need to install Shadow to check

william 2021-01-09T17:36:46.131300Z

I don't seem to have shadow-cljs globally installed, let's see

bbrinck 2021-01-09T17:37:34.132200Z

Hm, me either. And it’s not clear to me how shadow-cljs will pick up dependencies in that case. Maybe that’s a bad idea

bbrinck 2021-01-09T17:37:48.132800Z

Are you using deps.edn or lein for your project?

william 2021-01-09T17:37:52.132900Z

probably because I created a template using lein

william 2021-01-09T17:38:20.133400Z

so to create the template I used lein, but my deps are in a file called shadow-cljs.edn

bbrinck 2021-01-09T17:38:25.133700Z

ah, gotcha

bbrinck 2021-01-09T17:39:00.134200Z

Ah, OK, that makes sense. I will make a shadow-cljs.edn file now

william 2021-01-09T17:42:03.135Z

here's the command I used to create the project if it helps lein new reagent-frontend my-example +shadow-cljs

bbrinck 2021-01-09T17:45:13.135200Z

OK, here’s what I did

bbrinck 2021-01-09T17:45:41.135500Z

yarn shadow-cljs node-repl

bbrinck 2021-01-09T17:45:58.136Z

(and expound is in my dependencies in shadow-cljs.edn)

bbrinck 2021-01-09T17:46:20.136600Z

then I ran the sequence above and I did not get the expound output

william 2021-01-09T17:46:48.137100Z

interesting! Let me try, just for good measure, although I'm sure I won't get that either

william 2021-01-09T17:47:09.137700Z

but anyway, why would that happen?

bbrinck 2021-01-09T17:47:15.137900Z

In fact, it looks like shadow is printing the raw error object

bbrinck 2021-01-09T17:47:24.138300Z

#error {:message "Call to #'cljs.user/add1 did not conform to spec.", :data {:cljs.spec.alpha/problems [{:path [], :pred cljs.core/number?, :val (nil), :via [], :in []}], :cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha30168], :cljs.spec.alpha/value (nil), :cljs.spec.alpha/fn cljs.user/add1, :cljs.spec.alpha/args (nil), :cljs.spec.alpha/failure :instrument}}

william 2021-01-09T17:47:27.138600Z

the one that begins with #error

bbrinck 2021-01-09T17:47:31.139Z

exactly

william 2021-01-09T17:47:34.139300Z

yeah, that's what gets printed in emacs also

bbrinck 2021-01-09T17:47:58.139800Z

Ah, cool, this is helpful. So that’s not even the old error message - note that is different from what you get without shadow

william 2021-01-09T17:49:19.140400Z

that would be Execution error - invalid arguments to cljs.user/add1 at (<cljs repl>:1).?

bbrinck 2021-01-09T17:49:33.140800Z

Note that if you modify my other REPL (without expound) and you don’t call (set! s/*explain-out* expound/printer), you get the following

bbrinck 2021-01-09T17:49:43.141Z

Execution error - invalid arguments to cljs.user/add1 at (<cljs repl>:1).
(nil) - failed: number?

bbrinck 2021-01-09T17:49:47.141200Z

ha, yep, what you said 🙂

bbrinck 2021-01-09T17:50:11.141800Z

so anyway, my guess is that Shadow has it’s REPL configured to handle errors differently

bbrinck 2021-01-09T17:50:45.142Z

I’m googling now on how to adjust it

william 2021-01-09T17:51:56.142300Z

awesome 🙂

bbrinck 2021-01-09T17:58:55.143Z

Hm, I’m coming up empty so far. Basically if shadow lets you configure the REPL, we want to take that #error object and send the data to expound

william 2021-01-09T17:59:58.143800Z

I'm also googling, let's see what we can find; maybe it would be worthwhile to just ask in #shadow-cljs?

bbrinck 2021-01-09T18:03:00.144500Z

Yeah, I think maybe #shadow-cljs would know more. I’m super new to shadow

william 2021-01-09T18:03:02.144600Z

:repl-pprint ?

william 2021-01-09T18:03:52.145400Z

do you want me to ask or do you want to do that yourself? (I have the feeling you understand better what this is about)

bbrinck 2021-01-09T18:04:26.146200Z

Feel free to ask - I unfortunately need to leave in a few minutes

bbrinck 2021-01-09T18:04:57.147Z

But the general idea is that you want to turn that error into a string by calling expound/printer with the data. You can get inspiration from what CLJS does on the REPL: https://github.com/clojure/clojurescript/blob/5e88d3383e0f950c4de410d3d6ee11769f3714f4/src/main/cljs/cljs/repl.cljs#L218-L222

william 2021-01-09T18:05:49.147900Z

I'll do, thank you for all the help! 🙂

bbrinck 2021-01-09T18:06:02.148100Z

Good luck!

1🙏
bbrinck 2021-01-09T18:06:45.148900Z

If you figure it out, let me know here or in Github and I’ll add a section to the readme for Shadow

william 2021-01-09T18:07:05.149200Z

I will, thanks!

william 2021-01-09T21:13:46.149600Z

no progress yet, but I opened an issue here https://github.com/thheller/shadow-cljs/issues/825