7 ms·
> 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 exceptio
by 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.
- deleted 8y ago[deleted]
- yorwba 8y ago> You can't possibly know instantly all the exceptions to handle for a function (given it calls other functions w/ exceptions), You also can't possibly know all error codes to handle for a function if it calls other functions returning error codes, unless a type system enforces that for you. In which case you should compare to a language where the type system enforces that all exceptions are handled.
- JoshuaAshton 8y ago> You also can't possibly know all error codes to handle for a function if it calls other functions returning error codes You aren't using error codes or documenting correctly. You get a choice whether the error propogates upstream
- yorwba 8y agoExceptions can be documented just as well, and you have the same choice whether the error propagates upstream, only the default is different.
- JoshuaAshton 8y agoThe default idea behind exceptions is silly and as I stated before, they typically get generated to some horrific code
- maccard 8y agoI can make the same argument for exceptions - You're not documenting correctly. You also have the choice to ignore and fail with exceptions. Example: you have a method which requests a file from disk, but it fails to load for some reason. With error codes, you force all callers of your resource loader to explicitly handle the failure case at the point of failure, or you lose all context on the error. If you just bubble the error up, you're manually doing exceptions. With exceptions, the code that requests a file can assume it succeeds if it doesn't have enough context to handle the erorr, and you can handle at a higher level and still know what happened.
- deleted 8y ago
- otabdeveloper1 8y ago> You can't possibly know instantly all the exceptions to handle for a function And you never should. That indeed is horrible design. What you do need is a separation between 'exceptions that cause hard failure' v.s. 'exceptions that can lead to soft restarts'. You can easily separate them using common sense just looking at where your interface is located.
- 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.