3 ms·
Exceptions get a lot of hate, but of the three styles, I keep coming back to exceptions. Ages ago I built an application with error codes, and went back to exce
by rorylaitila 1y ago
Exceptions get a lot of hate, but of the three styles, I keep coming back to exceptions. Ages ago I built an application with error codes, and went back to exceptions, because I thought the ceremony of error checking was not worth it. On occasion, I'll use a get-last-error style, particularly when the error is something the user is intended to address. But for most of my applications (which are usually not libraries and are code under my control) I like exceptions.
I always have global error handler that logs and alerts of anything uncaught. This allows me to code the happy path. Most of the time, it's not worth figuring out how to continuing processing under every possible error, so to fail and bail is my default approach. If I later determine that its something that can be handled to continue processing, then I update that code path to handle that case.
Most of my code is web applications, so that is where I'm coming from.
- PaulHoule 1y agoHell yeah. I typed in my first C program, a terminal emulator, from a 1984 issue of Byte magazine. It was painful seeing how 5 lines of real logic were intertwined with 45 lines of error handling logic that, in the end, did what exceptions did for free -- it was a formative experience for me as a programmer and when I saw exceptions in Java in 1995 (still in beta) they made me so happy. In the async case you can pass the Exception as an object as opposed to throwing it but you're still left with the issue that the failure of one "task" in an asynchronous program can cause the failure of a supertask which is comprised of other tasks and handling that involves some thinking. That's chess whereas the stuff talked about in that article is Tic-Tac-Toe in comparison.
- rorylaitila 1y agoYeah, I agree in the async case. What I do there is wrapped the async code in its own global error handler, so to speak. That handler is logging to something that the outer process can get-last-error from. But I can get away with this also because I don't write async heavy code. My web applications are thread-per-request (Java). This fits 99% of the needs of business code, whose processing nature is mostly synchronous.
- PaulHoule 1y agoBy and large you want to avoid async if you can help it. Sometimes you can’t. The struggles Rustifarians have had with it are a cautionary tale (the stack and borrow checking go together like peanut butter and jelly.). I used to have a lot of fun writing async Python, friends told me I was living dangerously, I finally rewrote my RSS reader/bookmark manager/personal web crawler/image sorter in sync style so some of it could run in Celery and that any blocking on the CPU on a 16 core machine is too much. People used to worry about the 10k connection problem but machines are bigger now, few services are really that big, and fronting with nginx or something like that helps a lot. (That image sorter serves images with IIS) JavaScript is async and you gotta live with it because of deployability. No fight with the App Store. No installshield engineer. No army of IT people to deploy updates. “Just works” on PC, Mac, Linux, tablet, game consoles, VR headsets, etc. Kinda sad people are making waitlist forms with frameworks that couldn’t handle the kind of knowledge graph editor and decision support applications I was writing in 2006 but that’s life.
- bob1029 1y agoExceptions can even work with remote APIs. If you reach into the enterprise bucket of tricks, technologies like WCF/SOAP can propagate these across systems reliably. You can even forward the remote stack traces by turning on some scary flags in your app.config. When printing the final exception using .ToString(), this creates a really magical narrative of what the fuck happened. The entire reason exceptions are good is because of stack traces. It is amazing to me how many developers do not understand that having a stack trace at the exact instant of a bad thing is like having undetectable wall hacks in a competitive CS:GO match.
- rorylaitila 1y agoYes, I've never quite understood the "But with exceptions it's hard to debug why the error occurred after the fact, its better to be explicit in advance" - The stack trace points exactly to the line. And usually, with the error message and context, its all I need. Maybe I'm missing something that someone can inform me.
- flysand7 1y agoYeah, this kinda becomes a problem when the library you are using does not distribute its source code, so even if you get the line, this information is practically useless to you. This has been my biggest problem with exceptions, one, for the reason outlined above, plus it's for how much time you actually end up spending on figuring out what the exception for a certain situation is. "Oh you're making a database insertion, what's the error that's thrown if you get a constraint violation, I might want to handle that". And then it's all an adventure, because there's no way to know in advance. If the docs are good it's in the docs, otherwise "just try it" seems to be the way to do it.
- rorylaitila 1y agoYeah I agree with that, opaque errors from libraries are where this really sucks. The worst is when they swallow the original error and throw a generic exception instead.
- 1y ago
- PaulKeeble 1y agoAgreed and even more heretical from me is that I quite like declared exceptions. It makes the interface of a method clear in all the ways it can fail and you can directly choose what to handle often without having to look at the docs to work out what they mean, because the names tell you what you need to know. You can ignore them and rethrow catch globally but you can also handle them. Having used Go for years now frankly I prefer exceptions, way too often there is nothing that can be done about an error locally but it produces noise and if branches all over the code base and its even worse to add an error later to a method than in Java because every method has to have code added not just a signature change. I really miss stack traces and the current state of the art in Go has us writing code to produce them in every method.
- bigstrat2003 1y agoYep, checked exceptions are the shit. You can of course abuse them to create a monstrosity (as you can with anything), but when used responsibly I think they are by far the best error handling paradigm.
- vips7L 1y agoI agree but I still think checked exceptions, at least in Java, need more investment syntactically. They’re really painful with lambdas and you need to do weird things to get them to work properly; like rethrowing and catching some unchecked type. Scala has some interesting research here and describe the problem well [0]. Some other things I think that would go a long way to making checked exceptions more usable would be making try as an expression like in Scala or Kotlin. Not being an expression makes for some really awkward code or giant try blocks where you can’t tell what actually errors. Finally we really need a way to “uncheck” them unceremoniously. This is one of the largest reasons developers have rejected them. If you can’t possibly handle something you need to write at least 5-6 lines of code to wrap and throw in a runtime exception or you see developers checking things that they can’t handle and then their callers who also can’t handle those exceptions have to deal with the ceremony of unchecking. I’d really love for some `throws unchecked` or try! syntax that would just automatically turn something into a runtime exception: B func() throws AException; var b = try! func(); This all of course is probably a pipe dream, the OpenJdk team seems to be indefinitely stuck pouring all resources into Valhalla. [0] https://docs.scala-lang.org/scala3/reference/experimental/canthrow.html https://docs.scala-lang.org/scala3/reference/experimental/ca...
- o11c 1y agoThe problem with `getlasterror` and `errno` is that they're global (thread-local, whatever). But if you make them take a `context` object, there's no longer a problem. One interesting observation - you can use them even for the initial "failed to allocate a context" by interpreting a NULL pointer as always containing an "out of memory" error.
- vips7L 1y agoI love exceptions. I also think they’re the best mechanism of error handling, but in my experience a lot of developers just don’t seem to “get” exceptions. They seem to be scared of them from runtime crashes or they try to predict when they’ll happen instead of just catching/responding. I really think that’s because most implementations of exceptions are not checked. I really think that a language that invested in them properly more developers would come to see their value. I truly hope that will be Java some day. Making checked exceptions work across lambdas and providing language constructs to uncheck them would go miles.