This question is intended to apply to any OO programming language that supports exception handling; I am using C# for illustrative purposes only.
Exceptions are usually intended to be raised when an problem arises that the code cannot immediately handle, and then to be caught in a catch
clause in a different location (usually an outer stack frame).
Q: Are there any legitimate situations where exceptions are not thrown and caught, but simply returned from a method and then passed around as error objects?
This question came up for me because .NET 4's System.IObserver<T>.OnError
method suggests just that: exceptions being passed around as error objects.
Let's look at another scenario, validation. Let's say I am following conventional wisdom, and that I am therefore distinguishing between an error object type IValidationError
and a separate exception type ValidationException
that is used to report unexpected errors:
partial interface IValidationError { }
abstract partial class ValidationException : System.Exception
{
public abstract IValidationError[] ValidationErrors { get; }
}
(The System.Component.DataAnnotations
namespace does something quite similar.)
These types could be employed as follows:
partial interface IFoo { } // an immutable type
partial interface IFooBuilder // mutable counterpart to prepare instances of above type
{
bool IsValid(out IValidationError[] validationErrors); // true if no validation error occurs
IFoo Build(); // throws ValidationException if !IsValid(…)
}
Now I am wondering, could I not simplify the above to this:
partial class ValidationError : System.Exception { } // = IValidationError + ValidationException
partial interface IFoo { } // (unchanged)
partial interface IFooBuilder
{
bool IsValid(out ValidationError[] validationErrors);
IFoo Build(); // may throw ValidationError or sth. like AggregateException<ValidationError>
}
Q: What are the advantages and disadvantages of these two differing approaches?
Best Answer
If it is never thrown then it's not an exception. It is an object
derived
from an Exception class, though it does not follow the behavior. Calling it an Exception is purely semantics at this point, but I see nothing wrong with not throwing it. From my perspective, not throwing an exception is the exact same thing as an inner-function catching it and preventing it from propagating.Is it valid for a function to return exception objects?
Absolutely. Here is a short list of examples where this may be appropriate:
Is not throwing it bad?
Throwing an exception is kind of like: "Go to jail. Do not pass Go!" in the board game Monopoly. It tells a compiler to jump over all source code up to the catch without executing any of that source code. It doesn't have anything to do with errors, reporting or stopping bugs. I like to think of throwing an exception as a "super return" statement for a function. It returns execution of the code to somewhere much higher up than the original caller.
The important thing here is to understand that the true value of exceptions is in the
try/catch
pattern, and not the instantiation of the exception object. The exception object is just a state message.In your question you seem to be confusing the usage of these two things: a jumping to a handler of the exception, and the error state the exception represents. Just because you took an error state and wrapped it in an exception does not mean you are following the
try/catch
pattern or its benefits.