5 ms·
I tried and really wanted to like Clojure, but I hated the error messages. I love how it's a lisp, I love how you write programs in it, I love the REPL, it all
by twoquestions 10y ago
I tried and really wanted to like Clojure, but I hated the error messages. I love how it's a lisp, I love how you write programs in it, I love the REPL, it all just feels nice to me.... until I miskey something or make some other error. Then the compiler seems to hate me personally.
"Here's a haystack where the error /might/ be, have fun finding the needle dipshit." Maybe I'm just spoiled with Elm, Rust, and Elixir's error messages, but the last time I tried Clojure (more than a year ago) I just hit a wall when I tried to make a toy app, as the Clojure compiler seems to hate me even more than C's compiler does.
Has this situation improved? If so, I'd love to take another stab at it.
- jeremiep 10y agoI always use something like clj-stacktrace[1] to pretty print error messages and I've never had any issues figuring out what the problem was. Most of the time you're working from the REPL inside your editor anyways so the iteration loop is much, much better than any other language's. Even without clj-stacktrace I'd still prefer Clojure development to anything else. Rebooting a program and losing state is always worse than error messages taking a bit longer to understand at first. [1]: https://github.com/mmcgrana/clj-stacktrace https://github.com/mmcgrana/clj-stacktrace
- jgalt212 10y agothis seems a jillion times better than a standard stacktrace. why isn't it in built into the core?
- jeremiep 10y agoThe core just uses whatever the VM under it has for error handling. Clojure is a hosted language and one of the best decisions it made was not to hide the VM its sitting on (either the JVM, CLR or JS - all have slightly different exception handling). I see it more as a development library and don't ship it to production. There's also cljs-devtools and dirac to enhance the chrome devtools with ClojureScript support. Once you try them you're not going back :)
- jgalt212 10y agoI guess. But core could spit back a verbatim VM stacktrace and and Clojure specific/pretty printed version.
- misterbowfinger 10y agoRebooting a program and losing state is always worse than error messages taking a bit longer to understand at first. Not sure if it's _always_ worse. I've worked in imperative & functional languages, and the quality of error messages is key to solving bugs and understanding a sufficiently complex system, regardless of what language it's coded in.
- jeremiep 10y agoMaybe not always, but its important enough to consider. You often have much more information at runtime than at compile time. Sure I can run the compiler and scan its errors but I feel its much more productive to poke around the program as its running. Even when working in C++/whatnot I learn more about programs by running them in the debugger than reading the code (reading UE4's source code will be weeks of head scratching because its so huge - 2 days of stepping into its boot process and you know and _understand_ most of its architecture). I'd argue that the hardest bugs to find are the ones your type-system is completely helpless against. Few languages protect against null pointers and every time you have a cast you're breaking out of the type system and its guarantees. Dependent types aren't frequent either so you're now augmenting the type-system with asserts and guards and whatnot. I find that in C++/Java/C# complex systems are the norm because everything is built out of mutable blocks and misconceptions about what makes programs fast. Every project I did in Clojure was a fraction of the complexity it would've had in imperative languages. You're reducing complexity _so much_ that the "type-system is good for complex bugs" argument almost vanishes.
- misterbowfinger 10y ago... I learn more about programs by running them in the debugger than reading the code Agreed - in Ruby, most of my development was driven by a REPL & debugger, and tests. That's an example of a primarily imperative language, though it borrows some ideas from Lisp. But there, again, understanding error messages was key.
- lispm 10y agoThe example shows what's wrong: 1) bad error message. There error is explained in terms of some other machine, but not on the language level. 2) a zillion lines of useless stacktrace information: I don't want to debug the REPL, but the wrong call. The stacktrace also lacks argument information. Generally I would hope for a 'live' backtrace. > Most of the time you're working from the REPL inside your editor anyways so the iteration loop is much, much better than any other language's. Any other language, but not compared to those who have a similar or better REPL or debugger. Which is a zillion. > Rebooting a program and losing state is always worse than error messages taking a bit longer to understand at first. Not sure how that is related...
- emperorcezar 10y agoMy understanding is that the new spec system makes the error messages much better.
- nickik 10y agoClojure has added a new library called 'spec' and added alot of these specifications to the core of the language. These should help a lot with error messages, specially when using core libraries. See, http://clojure.org/about/spec http://clojure.org/about/spec Its still not great, but improvments are happening.
- twoquestions 10y agoThanks, I don't remember that being there the last time I was into Clojure, and I'll have to give that a try.
- jstewartmobile 10y agoI'm in the same boat. Unless you already have Java errors burned into your brain, it is very hard to decipher them in terms of Clojure code.
- kbp 10y agoIt's especially disappointing coming from Common Lisp and expecting a debugger with restarts etc on error. Just getting a stack trace feels so primitive.
- jeremiep 10y agoThat wouldn't be possible on the JVM. CL's condition system is unique to CL AFAIK. Even Emacs' cl module doesn't have this condition system. You really need support from the ground up to have it. Clojure is a hosted language, CL isn't. There are loads of tradeoffs from that design decision alone. Saying it feels primitive for that difference only is jumping to conclusions rather quickly! It feels like you're comparing decades of CL experience with days of Clojure experience :)
- junke 10y ago> Clojure is a hosted language, CL isn't. CL works on the JVM too (ABCL). There is a "java" layer where you can introspect classes and create them dynamically, etc. The syntax is not as terse as Clojure one's. There is one thing that I have had difficulties to do in Clojure, for example, is when you want to abstract over types: (fn [type] (.. type (staticFunction))) As far as I know, the above doesn't work because "type" is expected to be known at compile-time.
- kbp 10y agoThat difference does feel primitive, though; it's like a C-style edit->compile->run cycle vs talking to a listener. Like you said, tradeoffs, and Clojure definitely has a lot of other stuff going for it, but its version of interactive development is just a lot less interactive.