I have to say, I disagree completely. Results indicate the request was processed and the caller got what they asked. Exceptions indicate that something went wrong. There are two classes of exceptions: (i) system exceptions: unexpected issues that are not the fault of the caller. The caller can try again with the same request (but only if the method is marked as idempotent), and (ii) Request-related exceptions: issues that resulted from something wrong the the request, and indicating that the caller must change something before retrying.
For example in REST, 200 means result obtained, 50* means system error, and 40* means request error. The header status code neatly indicates what the resultant payload will be.
There are many REST advocates who suggest only using 200 responses for this very reason, and that HTTP status codes were not intended for REST error semantics.
I just think it's a shame that we can't use the built-in error mechanisms and have to bake our own.
This article is not about handling errors over a REST service. We used the Result object to return the result of a method in a class. See above example, I thought it was clear enough.
I implemented in the last years also some REST services and there I used the Statuscode of the response to indicate failed or successful operations. So we used the baked-in error handling solution and it worked well. Sometimes we return also a detailed error message/error code in the body, so I think my approach in doing REST server error handling was very similar to the Result object approach described in this article.
It's becoming clear to my that my choice of example was unfortunate, but the point I was trying to make is that the language (or protocol) provides error mechanisms, and we should preferably use these, rather than bake our own.
Results indicate the request was processed and the caller got what they asked.
This is not what a Result type represents. A Result is an abstract type that can represent either success or failure. A function that can fail should always return a result type, and it is up to the programmer to handle the Success case and the Failure case. The problem is, languages that already have exceptions built-in don't generally have a type-system that can accommodate Result types in a useful way.
If there were no built-in exceptions, you would be right - a result could be anything. That isn't the case, so a result in anything - it is the happy path. Everything else is an exception. Exceptions can have types and data...
The whole purpose of this article is to advocate a Result type as an alternative to exceptions. Like exceptions, they also have a type and associated data. But yes, they do not make sense in a language with exceptions.
This is not the reality of things though.
Check this post from Eric Lippert about how C# exceptions are usually used.
And most exceptions shouldn't even be thrown, if you, for example, supply an invalid string to a parser you ideally shouldn't get back an exception to handle (here Lippert's take.
And Eric Lippert was a part of C# design team.
The result pattern still makes sense for some use cases (for other TryDoSomething is better, for other Exception handling is the way to go), even in a language like C#.
Assuming Exceptions are always the way to go seems like a good recipe for sub-optimal design choices.
Assuming Exceptions are always the way to go seems like a good recipe for sub-optimal design choices.
I'm saying that exceptions are the most appropriate error handling mechanism in languages that have exceptions. I'm not saying every method should throw exceptions.
I agree that a Result would be more appropriate for the TryDoSomething pattern if we could throw everything out and redo it, but we can't. So, introducing a Result type means that we now have: exceptions, the TryDoSomething pattern, and a user-defined Result type.
Having so many ways of doing similar things is a sub-optimal design choice.
You are right, you have multiple options. I think the problem is you don't distuingish between the different types of errors. Depend on that you habe to choose the correct error handling mechanism. Doing all with exceptions is Not the correct way.
I have to say, I disagree completely. Results indicate the request was processed and the caller got what they asked. Exceptions indicate that something went wrong. There are two classes of exceptions: (i) system exceptions: unexpected issues that are not the fault of the caller. The caller can try again with the same request (but only if the method is marked as idempotent), and (ii) Request-related exceptions: issues that resulted from something wrong the the request, and indicating that the caller must change something before retrying.
For example in REST, 200 means result obtained, 50* means system error, and 40* means request error. The header status code neatly indicates what the resultant payload will be.
In your example I'd consider the http Response similar to a Result object.
There are many REST advocates who suggest only using 200 responses for this very reason, and that HTTP status codes were not intended for REST error semantics.
I just think it's a shame that we can't use the built-in error mechanisms and have to bake our own.
Well we're somewhat on the same page, I very much dislike getting 200 when something is not OK!
This article is not about handling errors over a REST service. We used the Result object to return the result of a method in a class. See above example, I thought it was clear enough.
I implemented in the last years also some REST services and there I used the Statuscode of the response to indicate failed or successful operations. So we used the baked-in error handling solution and it worked well. Sometimes we return also a detailed error message/error code in the body, so I think my approach in doing REST server error handling was very similar to the Result object approach described in this article.
It's becoming clear to my that my choice of example was unfortunate, but the point I was trying to make is that the language (or protocol) provides error mechanisms, and we should preferably use these, rather than bake our own.
This is not what a Result type represents. A Result is an abstract type that can represent either success or failure. A function that can fail should always return a result type, and it is up to the programmer to handle the Success case and the Failure case. The problem is, languages that already have exceptions built-in don't generally have a type-system that can accommodate Result types in a useful way.
If there were no built-in exceptions, you would be right - a result could be anything. That isn't the case, so a result in anything - it is the happy path. Everything else is an exception. Exceptions can have types and data...
The whole purpose of this article is to advocate a Result type as an alternative to exceptions. Like exceptions, they also have a type and associated data. But yes, they do not make sense in a language with exceptions.
This is not the reality of things though.
Check this post from Eric Lippert about how C# exceptions are usually used.
And most exceptions shouldn't even be thrown, if you, for example, supply an invalid string to a parser you ideally shouldn't get back an exception to handle (here Lippert's take.
And Eric Lippert was a part of C# design team.
The result pattern still makes sense for some use cases (for other TryDoSomething is better, for other Exception handling is the way to go), even in a language like C#.
Assuming Exceptions are always the way to go seems like a good recipe for sub-optimal design choices.
I'm saying that exceptions are the most appropriate error handling mechanism in languages that have exceptions. I'm not saying every method should throw exceptions.
I agree that a Result would be more appropriate for the
TryDoSomething
pattern if we could throw everything out and redo it, but we can't. So, introducing a Result type means that we now have: exceptions, theTryDoSomething
pattern, and a user-defined Result type.Having so many ways of doing similar things is a sub-optimal design choice.
You are right, you have multiple options. I think the problem is you don't distuingish between the different types of errors. Depend on that you habe to choose the correct error handling mechanism. Doing all with exceptions is Not the correct way.
Here is a great example using Result object: jimmybogard.com/domain-command-pat...