In order to handle several possible errors that shouldn't halt execution, I have an
error variable that clients can check and use to throw exceptions. Is this an Anti-Pattern? Is there a better way to handle this? For an example of this in action you can see PHP's mysqli API. Assume that visibility problems (accessors, public and private scope, is the variable in a class or global?) are handled correctly.
In order to handle several possible errors that shouldn't halt execution, I have an
If a language inherently supports exceptions, then it is preferred to throw exceptions and the clients can catch the exception if they do not want it to result in a failure. In fact, the clients of your code expect exceptions and will run into many bugs because they will not be checking the return values.
There are quite a few advantages to using exceptions if you have a choice.
Exceptions contain user readable error messages which can be used by the developers for debugging or even displayed to the users if so desired. If the consuming code cannot handle the exception, it can always log it so the developers can go through the logs without having to stop at every other trace to figure out what was the return value and map it in a table to figure out what was the actual exception.
With return values, there is no additional information can be easily provided. Some languages will support making method calls to get the last error message, so this concern is allayed a bit, but that requires the caller to make extra calls and sometimes will require access to a 'special object' that carries this information.
In the case of exception messages, I provide as much context as possible, such as:
Compare this to a return code -85. Which one would you prefer?
Exceptions usually also have detailed call stacks which help debug code faster and quicker, and can also be logged by the calling code if so desired. This allows the developers to pinpoint the issue usually to the exact line, and thus is very powerful. Once again, compare this to a log file with return values (such as a -85, 101, 0, etc.), which one would you prefer?
Fail fast biased approach
If a method is called somewhere that fails, it will throw an exception. The calling code has to either suppress the exception explicitly or it will fail. I have found this to be actually amazing because during development and testing (and even in production) the code fails quickly, forcing the developers to fix it. In the case of return values, if a check for a return value is missed, the error is silently ignored and the bug surfaces somewhere unexpected, usually with a much higher cost to debug and fix.
Wrapping and Unwrapping Exceptions
Exceptions can be wrapped inside other exceptions and then unwrapped if needed. For example, your code might throw
Simplicity of code
This one is a bit harder to explain, but I learnt through this coding both with return values as well as exceptions. The code that was written using return values would usually make a call and then have a series of checks on what the return value was. In some cases, it would make call to another method, and now will have another series of checks for the return values from that method. With exceptions, the exception handling is far simpler in most if not all cases. You have a try/catch/finally blocks, with the runtime trying its best to execute the code in the finally blocks for clean-up. Even nested try/catch/finally blocks are relatively easier to follow through and maintain than nested if/else and associated return values from multiple methods.
If the platform you are using supports exceptions (esp. such as Java or .NET), then you should not definitely assume that there is no other way except to throw exceptions because these platforms have guidelines to throw exceptions, and your clients are going to expect so. If I were using your library, I will not bother to check the return values because I expect exceptions to be thrown, that's how the world in these platforms is.
However, if it were C++, then it would be a bit more challenging to determine because a large codebase already exists with return codes, and a large number of developers are tuned to return values as opposed to exceptions (e.g. Windows is rife with HRESULTs). Furthermore, in many applications, it can be a performance issue too (or at least perceived to be).
Error variables are a relict from languages like C where exceptions were not available. Today, you should avoid them except you are writing a library which is potentially used from a C program (or a similar language without exception handling).
Of course, if you have a type of error which could be better classified as "warning" (= your library can deliver a valid result and the caller can ignore the warning if he thinks it is not important), then a status indicator in form of a variable can make sense even in languages with exceptions. But beware, callers of the library tend to ignore such warnings even if they should not, so think twice before introducing such a construct into your lib.
There are multiple ways to signal an error:
The problem of the error variable is that it is easy to forget to check.
The problem of exceptions is that is creates hidden paths of executions and although try/catch is easy to write, ensuring a proper recovery in the catch clause is really difficult to pull off (no support from type systems/compilers).
The problem of condition handlers is that they do not compose well: if you have dynamic code execution (virtual functions), then it is impossible to predict which conditions should be handled. Furthermore, if the same condition can be raised in several spots, there is no telling that a uniform solution can be applied each time... it quickly become messy.
Polymorphic returns (
The only issue is that they may potentially lead up to excessive checking; the languages that use them have idioms to chain the calls of functions that use them, but it may still require a bit more typing/clutter. In Haskell this would be monads, however this is far more scarier than it sounds, see Railway Oriented Programming.
I think it's awful. I'm currently refactoring a Java app that uses return values instead of exceptions. Although you may not at all be working with Java, I think this applies nonetheless.
You end up with code like this:
I'd much rather have the actions throw exceptions themselves, so you end up with something like:
You can wrap that in a try-catch, and get the message from the exception, or you can choose to ignore the exception, for example when you're deleting something that may already be gone. It also preserves your stack trace, if you have one. The methods themselves become easier, too. Instead of handling the exceptions themselves, they just throw what went wrong.
Current (horrible) code:
New and improved:
Strack trace is preserved and the message is available in the exception, rather than the useless "Something went wrong!".
You can, of course, supply better error messages, and you should. But this post is here because the current code I'm working on is a pain, and you shouldn't do the same.
"In order to handle several possible errors happening, that shouldn't halt execution,"
If you mean that the errors should not halt execution of the current function, but should be reported to the caller in some way - then you have a few options that have not really been mentioned. This case is really more a warning than an error. Throwing/Returning is not an option as that ends the current function. A single error message paramter or return only allows for at most one of these errors to occur.
Two patterns that I've used are:
What you pass to these collections/handlers should contain enough context for the error to be handled "correctly" - A string is usually too little, passing it some instance of Exception is often sensible - but sometimes frowned upon (as an abuse of Exceptions).
Typicial code using an error handler might look like this
There is often nothing wrong with using this pattern or that pattern, as long as you use the pattern that everyone else uses. In Objective-C development, the much preferred pattern is to pass a pointer where the method that is called can deposit an NSError object. Exceptions are reserved for programming errors and lead to a crash (unless you have Java or .NET programmers writing their first iPhone app). And this works quite well.
The question is already answered, but I can't help myself.
You can't really expect Exception to provide a solution for all use cases. Hammer anyone?
There are cases where Exceptions are not the end all and be all, for example, if a method receives a request and is responsible for validating all the fields passed, and not only the first one then you have to think that it should be possible to indicate the cause of the error for more than one fields. It should be possible to also indicate if the nature of the validation prevents the user from going further or not. An example of that would be a not strong password. You could show a message to the user indicating that the entered password is not very strong, but that it is strong enough.
You could argue that all of these validations could be thrown as an exception at the end of the validation module, but they would be error codes in anything but in the name.
So the lesson here is: Exceptions have their places, as do error codes. Chose wisely.
There are use cases were error codes are preferable to exceptions.
If your code can continue despite the error, but it needs reporting, then an exception is a poor choice because exceptions terminate the flow. For example, if you're reading in a data file and discover it contains some non-terminal piece of bad data it might be better to read in the rest of the file and report the error rather than fail outright.
The other answers have covered why exceptions should be preferred to error codes in general.
There's definitely nothing wrong with not using exceptions when exceptions are not a good fit.
When the code execution should not be interrupted (e.g. acting on user input that may contain multiple errors, like a program to compile or a form to process), I find that collecting errors in error variables like
In some dynamic programming languages you can use both error values and exception handling. This is done by returning unthrown exception object in place of ordinary return value, which can be checked like an error value, but it throws an exception if it isn't checked.
In Perl 6 it is done via
In Perl 5 you can use Contextual::Return you can do this with
Unless there is something very specific, I think having an error variable for validation is a bad idea. The purpose seems to be about saving the time spent on validation (you can just return the variable value)
But then if you change anything, you have to recompute that value anyway. I can't say more about halting and Exception throwing though.
EDIT: I didn't realize this is a question of software paradigm instead of a specific case.
Let me further clarify my points in a particular case of mine in which my answer would make sense
There are two kinds of errors:
In the service layer, there is no choice but using Result object as wrapper which is the equivalence of error variable. Simulating an exception via service call on protocol like http is possible, but is definitely not a good thing to do. I am not talking about this kind of error and didn't think this is the kind of error being asked in this question.
I was thinking about the second kind of error. And my answer is about this second kind of errors. In the entity objects, there are choices for us, some of them are
Using validation variable is the same as having a single validation method for each entity object. In particular, the user can set the value in a way that keep the setter as purely setter, no side effect (this is often a good practice) or one can incorporate validation into each setter and then save the result into a validation variable. The advantage of this would be to save time, the validation result is cached into the validation variable so that when the user calls validation() multiple time, there is no need to do multiple validation.
The best thing to do in this case is using a single validation method without even using any validation to cache validation error. This helps keep the setter as just setter.