7 ms·
Exceptions are clearly superior to error codes in most cases. Easier to maintain, easier to handle, and you can attach much more contextual information to them.
by victorstanciu 8y ago
Exceptions are clearly superior to error codes in most cases. Easier to maintain, easier to handle, and you can attach much more contextual information to them.
Shameless plug for my open source PHP error handler: https://github.com/slashtrace/slashtrace https://github.com/slashtrace/slashtrace. I use it as a catch-all mechanism that displays detailed information about the error when running in a development environment, but sends the data to an external service (Sentry in my case) when in production.
Obviously there are a ton of places in the code where you want to catch and handle exceptions yourself, but having a catch-all acts as a safety net.
I do like their approach of logging stats for exceptions that don't represent system errors, but which they monitor anyway (like the BadClientRequestException).
- enriquto 8y ago> Exceptions are clearly superior to error codes in most cases. I disagree with this, on a very strong and deep sense. When you program, there are no exceptional cases. All possible behaviors should be treated on equal footing, using the control structures of your language. When you try to open a file, either you can or you cannot, and none of these two cases is exceptional in any way. I would rather say that a programming language that supports exceptions is broken by design. If the language even forces you to use the exceptions, then it leads inevitably to spaghetti code.
- otabdeveloper1 8y ago> I disagree with this, on a very strong and deep sense. That's because you're inexperienced. > All possible behaviors should be treated on equal footing, using the control structures of your language. That's impossible if you're dealing with a system composed of multiple interacting abstraction layers. An error inside a function precondition is not the same as an error crashing a thread of execution, which in turn is not the same as an error in logical consistency communicating between different services. The "equal footing" you're talking about can only exist if you're dealing with very simple and linear programs.
- JoshuaAshton 8y ago> That's because you're inexperienced. That's fairly rude to the guy, and doesn't make your point any stronger. I've worked with exceptions before, it leads to try/catch spaghetti code. You can't possibly know instantly all the exceptions to handle for a function (given it calls other functions w/ exceptions), whereas, if it returns a fixed bunch of error codes, then you can know why that specific function failed and handle appropriately. Doesn't help that (language) exceptions typically have awful codegen. There's a reason nobody uses them in game-dev.
- joshuagvk 8y agoI might be misunderstanding, but doesn't this > You can't possibly know instantly all the exceptions to handle for a function (given it calls other functions w/ exceptions), whereas, if it returns a fixed bunch of error codes, then you can know why that specific function failed and handle appropriately. presume that, despite not being able to know all exceptions to handle in advance, you somehow have knowledge of all error conditions in the event that you're using error codes?
- enriquto 8y ago> presume that, despite not being able to know all exceptions to handle in advance, you somehow have knowledge of all error conditions in the event that you're using error codes? I guess that it is indeed the case. If you call one function, you can read the documentation of said function and read about its return values, including error codes. This specification cannot not change if one of the libraries nested deep within this function is replaced. However, with exceptions, if you use a new implementation of a deeply nested function it may raise a new exception that nobody was aware of at the time of writing the outermost functions.
- JoshuaAshton 8y agoUsually documentation tends to have this, or you can look at the function and immediately know what it will return, whereas with exceptions any passthrough errors are transparent.
- ganonm 8y agoThe fact they are typically referred to as exceptions has nothing to do with the fact that they are exceptional or not. Exceptions, in an abstract sense, are a language feature that allows exiting from functions via an alternative mechanism to traditional 'return' statements. The main advantage (just picking reasons off the top of my head) is that you can write your code as if it will certainly succeed, then have a separate block of code for handling failure cases. This makes code a lot more legible and draws explicit attention to failure case handling. Some languages make a distinction between 'checked' and 'unchecked' exceptions (e.g. Java) whereby checked exceptions must be handled at the call-site, whereas unchecked exceptions can be caught anywhere in the call stack (or not at all, in which case the thread or program will terminate). It is often conventional to forego checked exceptions and only use unchecked exceptions to provide flexibility to the caller in where they handle the exception. Some languages such as Kotlin remove the concept of checked exceptions from the language entirely. Languages like C which don't have exception handling force the programmer to use return code checking to verify if a method call has succeeded. This is fine, but as I alluded to above, can add noise to code and diminishes flexibility. One example of the power of unchecked exceptions is e.g. an exception mapper in a REST server. This allows the programmer to throw an unchecked exception at any point in the server application code and this will (if not handled by the application code explicitly) get caught by the exception mapper. It will then map this exception to an appropriate HTTP response code and return it to the API user. An argument against exceptions is that there is a large 'overhead' to handling them. I've yet to see a scenario where an application performance bottleneck is being caused by exceptions. YMMV.
- ken 8y ago> The fact they are typically referred to as exceptions has nothing to do with the fact that they are exceptional or not. Yet there's millions of google hits for "exceptions should be exceptional" and variations of it. This meme has taken hold in a big way. I've tried to use them in other ways -- after all, as the author of a program, how can I possibly know which branch will be the common one, for the user? -- and I always get beaten down by other developers with this aphorism. As this article points out: "The naming of ‘Exception’ is actually quite unfortunate."
- wDcBKgt66V8WDs 8y agoThere are some functions for which we know things will break eventually, e.g. a db call. We want to catch those situations, no pun intended. Our options are: return codes, or exceptions. In the return code case, we're using if/then to handle error situations. In the exception code, we're using try/catch. With respect to spaghetti, they're literally the same thing, just differently indented...
- wDcBKgt66V8WDs 8y agoMeanwhile in the land of PHP I'm convinced that forcing paranoid error levels and converting all errors to exceptions is the only safe way to develop. Too many times in PHP the return type of a function is not what was expected from documentation and I'm not about to do type checking in addition to value checking every function result. Ridiculous. So type-aware comparisons and errors to exceptions it is. Whatever code called a file that managed to hit a bad return type can now continue living and logging instead of `PHP Fatal error` edit: or the PHP special of hitting an error down the stack and again just dying without passing the message up the chain. That is no way to work.
- victorstanciu 8y ago> forcing paranoid error levels and converting all errors to exceptions is the only safe way to develop Oh, absolutely. That's how I do it too. Unfortunately, warnings and notices are still a thing in PHP 7. So the best practice is to just install an error handler that turns these into exceptions. They they are either handled by code, or by a catch-all handler. This is in fact what I've implemented SlashTrace to do by default: https://github.com/slashtrace/slashtrace/blob/master/src/ErrorHandler.php#L38 https://github.com/slashtrace/slashtrace/blob/master/src/Err...
- krispbyte 8y agoThe alternative is the Result or Maybe objects with pattern matching from functional languages. It seems similar to return codes with if/then, but the strong typing and the match forcing you to deal with all possible branches (or pass it along) makes it less spaghetti looking.
- Tarean 8y agoSo division by zero should be handled the same way as network timeout? Because that math code is gonna be verbose. Error codes and exceptions are both awful for control flow. Typed errors and checked exceptions work better for known errors but break down for IO because you can't handle all IO errors - new OS versions can add new ones. And all of these are awkward when propagating errors between threads.
- rcfox 8y agoSay you have library that takes a filename and returns the contents after some kind of decoding. If the file is inaccessible (doesn't exist, in use, user doesn't have permission), you don't want the library to take any real action on that. It shouldn't display a message, attempt to correct the filename or retry the same file. It should just let the caller know that an error occurred, and ideally what that error was. Okay, so we'll return early with an error code and probably some kind of nil result. (Because we're not using a system that's so archaic that it can only return one value!) But the caller of the library was some middleware that also can't be expected to handle the error usefully. It returns the same error and result to its own caller. And let's say there are a few layers like this until we finally get to the top layer where we can translate that error code into a big, red message for the user saying "file not found". Now how is that any different from raising an exception? (Other than the extra 'if error: return error, result' lines you need.)
- wyldfire 8y ago> Now how is that any different from raising an exception? (Other than the extra 'if error: return error, result' lines you need.) I think exceptions can be used well in some contexts but I will completely concede the point that they're super complicated. "How is that any different?" Well -- we unwound the stack automagically and that's not trivial. Every intervening piece of code should know that a call they make could transitively make lots of interesting calls and they might cause this function we're writing to exit early.
- kaoD 8y ago> Now how is that any different from raising an exception? Exception bubbling is implicit. There's no way to know which exceptions can be thrown from a function just by looking at its code, nor looking at the called-functions code. You have to keep in your head all the call chain up to the first function that does not call any other function (good luck with that). Even worse: we don't even know _where_ the function can stop running and start unwinding. This leads to defensive programming. Hello try-catch soup! It's a slippery slope that gets worse and worse with each abstraction layer. Languages with typed errors have been nothing but a joy for me.
- wvenable 8y agoI disagree with this, on a very strong and deep sense! Invariably you will have error conditions; situations that are expected work in order for your application to function. Your application is expected to open a file to work, if it can't open the file then that's an error. Your program cannot continue to do whatever it was supposed to do. You make a call and it can't do it's job. So it returns to you an error and maybe that means that you can't do your job now. So you return an error to your caller. And if you do that all perfectly, you're basically doing exception handling without any help from the language.
- adlpz 8y agoSlashtrace looks very interesting. Any pointers on how would it integrate with frameworks with built-in catch-all handlers for dev, like Symfony?
- victorstanciu 8y agoHmm, I haven't given it that much thought yet. Maybe I should start writing integration guides for the major frameworks. You are more than welcome to open a GitHub issue about this, and I'll get to it.
- andrewmcwatters 8y agolooks like whoops http://filp.github.io/whoops/ http://filp.github.io/whoops/
- jimmy1 8y agoExceptions are clearly inferior to an alternative strategy of handling errors as values rather than something exceptional to catch. Exceptions to me started off as a humble concept (if something truly exceptional happens, do x y or z, but in 99% of cases you will probably just want to abort or crash) Instead exceptions have become every day errors. Like the article defines, > The handling of exceptional cases; perhaps a service failed for an unexpected reason like a network failure Really? A service failure or network failure is an exceptional case for you? This should be planned for, and built into the architecture! Plan for the network always failing! Recover gracefully! That is what retry strategies like exponential backoff are for, and circuit breakers, idempotent requests so you can simply cancel and try again, so on and so forth. Instead of treating everything as exceptional, when you treat errors as values, they lend you down the path of actually handling them. As a side effect of this, you build more robust systems. Bubbling up an error to the top when errors are values are seen as an anti-pattern, only to be done in the most rare of circumstances. Again, from the article, > All other exceptions - Signifies my server has a bug Then your server should crash! Take it out of the load balancer, stop the damage! If you truly can't classify it, it's truly unknown or exceptional, abort!
- orf 8y agoDon't confuse the name "exceptions" with the English definition. They are just a mechanism for returning values, usually signifying errors (but not always: see Python StopIteration), without using a standard 'return'. So no, nobody is considering a network failure an exceptional case.
- ec109685 8y ago> Then your server should crash! Take it out of the load balancer, stop the damage! If you truly can't classify it, it's truly unknown or exceptional, abort! What if all the servers have the same bug? Should they all crash or should they alert and allow an operator to chose how to handle? If it is a rarely hit error case, staying up is better than creating a complete outage.
- wvenable 8y ago> Really? A service failure or network failure is an exceptional case for you? This should be planned for, and built into the architecture! Plan for the network always failing! Recover gracefully! Exception do let you plan for exactly that while ignoring the ridiculous notion that you can know every possible error that every function can trigger now or in the future. Instead you plan for exactly where you can restart a network operation in the code and put your exception handler in that spot. You don't need to do anything else. It's simple and effective. The alternative is to write a lot of boilerplate code that does nothing but get you to that same point.
- ken 8y agoConditions are clearly superior to exceptions in most cases. I don't understand the point of exceptions. It's like saying I want a status reporting feature with power and flexibility and meaning, but not that much power and flexibility and meaning.