5 ms·
One of the main reasons I don't even want to touch Clojure is because I don't want to be trying to figure out Java stacktraces when things go wrong.
by pmoriarty 4y ago
One of the main reasons I don't even want to touch Clojure is because I don't want to be trying to figure out Java stacktraces when things go wrong.
- fuzzythinker 4y agoClojure doesn't need JVM. You can run it with GraalVM either directly [1] or via Babashka [2]. Both are great options for get into Clojure. [1] https://github.com/oracle/graal https://github.com/oracle/graal [2] https://github.com/babashka/babashka https://github.com/babashka/babashka
- selimco 4y agoTechnically, graal is also a JVM. Do you mean native image by any chance?
- capableweb 4y agoTechnically, I think it's more correct to say GraalVM includes/has a JVM, it runs a couple of languages, not just JVM based ones.
- kaba0 4y agoWhat’s bad about Java stacktraces?
- vaylian 4y agoThe problem is that the stacktrace shows you all the gory JVM details that are irrelevant to your Clojure code. Even when your code is 100% Clojure, the Java classes, that are the foundation for Clojure, are shining through when you get the stacktrace. It's been a while since I last used Clojure, so I don't know if the situation has improved in the meantime.
- thom 4y agoFor what it’s worth, it’s very easy to filter stack traces in most Clojure tooling. You don’t have to look at anything but your code, or just Clojure code etc. Obviously you’re still looking at Java exceptions for the most part, but I’ve never found being on top of the JVM as icky as some others obviously do.
- Bost 4y agoEven such a filter is too often useless. Like, 4 out of 5 times. I rely more on logging and parameter inspection. E.g.: (defn foo [a b] (def a a) (def b b) (/ a b)) If the function fails, I have captured its input parameters right before the exception occurred and now I can inspect it from the REPL if 'b' is 0. From the REPL I can change the value of 'b' with simple `(def b 42)` or change the very definition of 'foo' and re-evaluate it again on the REPL with simple `(foo a b)`. I even made myself an elisp function for inserting the '(def a a)' into the code https://github.com/Bost/corona_cases/blob/master/.dir-locals.el#L86 https://github.com/Bost/corona_cases/blob/master/.dir-locals... (enjoy).
- thom 4y agoWould CIDER's interactive debugger not be more straightforward here?
- Bost 4y agoThat's not an IDE agnostic approach. IIRC after modifying and reevaluating the function inside which the debugger is currently in, the debug session is terminated and the evaluation context i.e. the values of input parameters are lost. Even if the session can be restored I'm not sure if it survives a REPL restart. And even if it does I'm not sure if it survives a reboot, unlike my approach. Moreover, this approach with defs allows you to inspect every function, even those macro generated. And if committed, such a "debug session" is persistent across every instance where the code is deployed, from any development machine, through all test and staging machines right into production. (So when combined with some remote REPL access... you see what I mean?) Another thing is that I like when my code strongly express the notion of compositionality, i.e. when it looks something like this: (comp ... (partial map ...) foo3 (partial reduce ...) (fn [p] (def s3 p) p) (partial map ...) (fn [p] (def s2 p) p) (partial apply ...) (partial map ...) foo2 (fn [p] (def s1 p) p) foo1 (partial apply ...) (partial map ...)) here I introduce and comment in/out the '(fn [p] ...)' expressions as needed. That kills two birds with one stone. 's1' captures the output of 'foo1' which is also the input of 'foo2' at the same time.
- vkazanov 4y agostrict answer: they are very deep. informal coffee break answer: abstracted layers of abstracted abstraction within parametrized abstractions just don't feel right to lispers.
- Bost 4y agoFYI you're writing this post on a device which is a product of millions of ideas and inventions all of them refined, abstracted and parametrized thousands of times, if not even more.
- vkazanov 4y agoHave you ever seen Java/Clojure stacks? :-) My browser is cpp program. Say, 10 layers are typical. Then, there's a libc + ui linux code. Usually in c, so even less layers. Say, 10 more. Then, there are sycalls annoying the kernel from time to time. Pretty shallow, btw, 5. That's 30 roughly speaking. Maybe 40. Java + clojure combo is not impressed, not at all.
- AtNightWeCode 4y agoThe page count
- wiseowise 4y agoIt’s quite silly to complain about such minor “issue”, don’t you think? Compared to what being hosted language gives you.
- Bost 4y agoI'm sorry but this as an argument is weak. Yes, it is true, the stacktraces are terrible, bordering on useless noise, but that doesn't mean that "exceptions & stacktraces" is the only possible approach when it comes to error handling.
- kubb 4y agoIf this is one of the main reasons, then the case against Closure that you're making doesn't sound very strong.
- didibus 4y agoYa, if you've never programmed in Java, Kotlin or Scala on the JVM before, this is definitely an additional learning that all JVM languages have. But if you're already familiar with any of those, it'll be the same as what you're used too.
- roguas 4y agoTo a degree. Interop is useful, but you can getby with most of things without it. Long term you will learn interop as it's often times easier to write small piece of code to take java lib, rather than trusting in community wrappers.