Fork me on GitHub
#clojure-dev
<
2018-02-09
>
bronsa00:02:37

that's definitely a mistake

seancorfield01:02:33

So I guess the real question is "What tooling is coming out of Cognitect that relies on the new 'program REPL'?"

seancorfield01:02:37

And will we see CIDER, Cursive, and ProtoREPL offer options to connect to a prepl instead of nrepl soon? šŸ™‚

cfleming01:02:57

It looks similar to unrepl.

cfleming01:02:15

At least, the basic interaction model (streaming input, structured output)

cgrand08:02:38

So I wasnā€™t totally wrong:-)

cfleming10:02:50

Haha, not at all! šŸ™‚

cfleming01:02:31

I donā€™t know where the CIDER team are up to, they were working on decoupling CIDER and refactor-clj from nREPL, but thatā€™s a big job.

bhauman14:02:39

I'm liking the prepl implementation, the only thing that sticks out at me is the lack of differentiation between thrown exceptions and intentionally returned exception values

Alex Miller (Clojure team)14:02:30

the latter seems quite rare

bhauman14:02:16

for sure it is but I do it in the repl sometimes to check the creation of exceptions, guess I'm a weirdo

mpenet14:02:50

Could happen with core.async since there s no built in error handling: promise-chan around some java async op returning a "normal" value or an exception instance

mpenet14:02:22

I guess it s more of a last resort thing, but it s plausible

bhauman14:02:54

the other thing that I haven't quite wrapped my head around is the possible meaning and interaction of something like tap> (who's intended purpose I'm assume is to aid with tooling messages) in the strange world of ClojureScript where much of the data that tooling needs lives in a clojure process yet tap would be evaled in the clojurescript process?

bhauman14:02:32

(cljs.core/tap> {:completion (cljs.tooling/completion-macro "asso")})

bhauman14:02:20

where cljs.core/tap> itself is a macro

bhauman15:02:25

while this is clean, it has the unfortunate requirement of sending everything to the javascript environment and doesn't allow short-cutting

bronsa16:02:59

by that case Iā€™m referring to returned exception values

bhauman16:02:42

makes sense

seancorfield18:02:31

@alexmiller I was chatting about this with my co-worker @hiredman yesterday and the lack of differentiation of exceptions from returned values was something we both felt was lacking in prepl.

seancorfield18:02:53

Well, part of the problem is that because an exception is returned as a printed hash map, you can't even really tell it's not just a result. I would expect tooling authors would like to be able to tell the difference?

Alex Miller (Clojure team)19:02:24

given your context is a repl, how would you handle the two cases differently?

Alex Miller (Clojure team)19:02:36

determining that it is an exception at all is I think a more interesting question, but Iā€™m not sure itā€™s a different question than being able to differentiate any two maps that have different but known structures

seancorfield19:02:22

Since this is a REPL aimed at programs, I would say it's important that those programs can tell that an expression failed to read or failed to evaluate easily. Error handling seems like an important use case here.

Alex Miller (Clojure team)19:02:54

repls typically ā€œprintā€ both a response and a thrown exception

Alex Miller (Clojure team)19:02:46

if you can tell that the response is an exception and ā€œprintā€ it appropriately, I think thatā€™s sufficient

seancorfield19:02:51

Which is fine when presenting the data to a user (although nice REPLs pretty-print an exception with colors and suppress "noise" in the output).

Alex Miller (Clojure team)19:02:24

those capabilities still exist

seancorfield19:02:01

prepl could easily set different :tag values for exceptions -- and I would argue that an exception from read and an exception from eval would benefit from being tagged differently (but that's perhaps splitting hairs)

seancorfield19:02:47

Right now, if a program gets a :ret back, it has no idea whether the evaluation succeeded or failed. That's the point.

Alex Miller (Clojure team)19:02:40

assuming you knew that the ret value was the form of an exception, then if you get one of those, it failed

Alex Miller (Clojure team)19:02:16

Iā€™m not sure that itā€™s relevant whether it failed during read or evaluation

Alex Miller (Clojure team)19:02:05

in all of these cases (exception during read, exception during eval, return value is an exception), a repl does the same thing: it prints the exception

Alex Miller (Clojure team)19:02:05

maybe relevant to have a predicate to ask: does this map represent an exception?

Alex Miller (Clojure team)19:02:25

Iā€™m not trying to be a pain about this, really just trying to push against adding more stuff if itā€™s not actually needed

Alex Miller (Clojure team)19:02:48

and maybe it is needed and weā€™ll find that and it will change

seancorfield18:02:06

Definitely nice to be able to specify -Dclojure.server.thing='{:port 5555 :accept clojure.core.server/io-repl}' when starting a JVM process and have a program REPL available tho'...

Alex Miller (Clojure team)18:02:05

once I get the quoting sorted out for JVM opts, you can stuff that all in an alias too :)

Alex Miller (Clojure team)18:02:19

or maybe weā€™ll just make a switch for it, tbd

seancorfield18:02:53

Well, part of the problem is that because an exception is returned as a printed hash map, you can't even really tell it's not just a result. I would expect tooling authors would like to be able to tell the difference?

gfredericks21:02:37

as a user I think it's important for me to be shown the difference between a thrown and returned exception; I disagree that repls do the same thing in either case (just print the exception), though that might be true for the most basic repl

seancorfield21:02:12

@gfredericks glad I'm not the only one šŸ™‚

gfredericks21:02:08

e.g., currently I use cider and it pops up another buffer when an exception is thrown, which is rather jarring in a way that seems sort of appropriate (even if I might prefer it slightly differently, like printed in red in the repl buffer) if I eval something that returns an exception, I'd want it to calmly print data like it does for anything else

gfredericks21:02:54

I think I've programmed before in contexts where you can't tell the difference, and have found myself having to write try/catch code that wraps things just so I can figure out what's going on

bhauman22:02:28

the current clojure,main/repl-caught function provides different behavior when its a thrown exception and benefits from the differentiation

Alex Miller (Clojure team)22:02:34

true, although I think when we circled back to look at it during the socket repl work, we regretted that :)

gfredericks22:02:59

what was regrettable?

Alex Miller (Clojure team)22:02:02

that it did something different, and also, what it did :) we went a ways down a path on changing that but eventually undid most of it. but that path is where Throwable->map showed up

gfredericks22:02:45

is it just a "more code than necessary" problem, or does doing something different make something else more difficult?

gfredericks22:02:07

users can opt-out of the distinction, can't they?

Alex Miller (Clojure team)22:02:33

I actually havenā€™t talked to Rich about this (yet) but clearly he made a conscious choice here

seancorfield22:02:12

Thinking about this some more, I guess tools can tell the difference between a successful eval and one that threw -- and even whether read failed:

{:tag :ret ; could be exception from read, exception from eval, or result
:val ... ; Throwable->map or result
:form ... ; only present if read succeeded
:ms ... ; only present if eval succeeded
:ns ...} ; always present
It feels a bit hinky to check for :ms and :form to determine what :val is but doable. Although I would want some assurances from @alexmiller (or Rich!) that those keys would not "change" in terms of being there or not.

bhauman22:02:02

well that is enough for me

bhauman22:02:36

thanks for pointing that out