This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-02-09
Channels
- # beginners (205)
- # boot (6)
- # cider (22)
- # cljs-dev (41)
- # cljsrn (4)
- # clojure (97)
- # clojure-dev (61)
- # clojure-greece (40)
- # clojure-italy (8)
- # clojure-russia (16)
- # clojure-spec (18)
- # clojure-uk (34)
- # clojurescript (14)
- # community-development (1)
- # cursive (45)
- # datomic (39)
- # fulcro (66)
- # jobs (2)
- # lein-figwheel (1)
- # lumo (9)
- # off-topic (8)
- # parinfer (98)
- # portkey (8)
- # re-frame (81)
- # reagent (54)
- # remote-jobs (17)
- # ring (2)
- # shadow-cljs (217)
- # spacemacs (32)
- # sql (24)
- # test-check (6)
- # unrepl (73)
- # yada (12)
Shouldn't it be *in*
here https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L3766 (to match what read
does)?
So I guess the real question is "What tooling is coming out of Cognitect that relies on the new 'program REPL'?"
And will we see CIDER, Cursive, and ProtoREPL offer options to connect to a prepl instead of nrepl soon? š
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.
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
the latter seems quite rare
for sure it is but I do it in the repl sometimes to check the creation of exceptions, guess I'm a weirdo
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
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?
while this is clean, it has the unfortunate requirement of sending everything to the javascript environment and doesn't allow short-cutting
@bhauman @alexmiller tools.analyzer.jvm/analyze+eval
handles that case like this https://github.com/Bronsa/tools.analyzer.jvm/blob/master/src/main/clojure/clojure/tools/analyzer/jvm.clj#L521-L523
@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.
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?
given your context is a repl, how would you handle the two cases differently?
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
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.
repls typically āprintā both a response and a thrown exception
if you can tell that the response is an exception and āprintā it appropriately, I think thatās sufficient
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).
those capabilities still exist
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)
Right now, if a program gets a :ret
back, it has no idea whether the evaluation succeeded or failed. That's the point.
assuming you knew that the ret value was the form of an exception, then if you get one of those, it failed
Iām not sure that itās relevant whether it failed during read or evaluation
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
maybe relevant to have a predicate to ask: does this map represent an exception?
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
and maybe it is needed and weāll find that and it will change
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'...
once I get the quoting sorted out for JVM opts, you can stuff that all in an alias too :)
or maybe weāll just make a switch for it, tbd
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?
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
@gfredericks glad I'm not the only one š
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
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
</ 2Ā¢>
the current clojure,main/repl-caught function provides different behavior when its a thrown exception and benefits from the differentiation
true, although I think when we circled back to look at it during the socket repl work, we regretted that :)
what was regrettable?
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
is it just a "more code than necessary" problem, or does doing something different make something else more difficult?
users can opt-out of the distinction, can't they?
less is more
I actually havenāt talked to Rich about this (yet) but clearly he made a conscious choice here
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.