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

alexmiller14: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?

alexmiller19:02:24

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

alexmiller19: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.

alexmiller19:02:54

repls typically “print” both a response and a thrown exception

alexmiller19: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).

alexmiller19: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.

alexmiller19:02:40

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

alexmiller19:02:16

I’m not sure that it’s relevant whether it failed during read or evaluation

alexmiller19: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

alexmiller19:02:05

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

alexmiller19: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

alexmiller19: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'...

alexmiller18:02:05

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

alexmiller18:02:19

or maybe we’ll just make a switch for it, tbd

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

alexmiller22: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?

alexmiller22: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?

alexmiller22:02:45

less is more

alexmiller22: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