Proposal to make Result a class instead of a struct
See original GitHub issueResult is currently a struct. (Actually, three structs, because of Result<T> and Result<T, E> as well.)
Unfortunately, this creates rather a lot of complications.
-
Implicit conversion operators are required to convert between the different structs, since there is no inheritance. In particular, the implicit conversions from
Result<T, E>toResult<T>/Resultactually callToString()on theEerror value, which seems rather presumptuous. Some Map() overloads rely on this conversion to get from one Result type to another, so custom errors could conceivably lose fidelity in the process. -
The logic for creating Results is encapsulated in a special class
ResultCommonLogic, an instance of which is then stored on everyResult. This adds complexity and overhead. In spite of this, there is inevitably still plenty of code duplication. -
Issue #125 highlights the requirement for a non-value
Resultwith a custom error type, something that would add yet another struct to the mix, whereas a base class might be a more fitting solution. -
There are challenges ahead with managing and improving extension overloads (see #146), some of which might be alleviated with some judicious use of class inheritance. (I am still investigating this).
I propose switching Result back to a class and leveraging inheritance to solve these problems. Based on my experiments so far, I think we might achieve a significant reduction in complexity, and improve maintainability.
Here are two possible approaches. Note how in both cases the base class is a new non-value result with generic E error type, solving #125):
(1) Maintain current types
class ResultBase<E> {}
class Result : ResultBase<string> {}
class Result<T, E> : ResultBase<E> {}
class Result<T> : Result<T, string> {}
(2) This may be cleaner and more intuitive, but will break more
class Result<E> {}
class Result : Result<string> {}
class ValueResult<T, E> : Result<E> {}
class ValueResult<T> : ValueResult<T, string> {}
I have started playing around with an implementation of the first approach and I am very encouraged, with complexity falling away as I progress. I still want to experiment with the second syntax though.
#99 is another (minor) issue that would be solved by this change. There are probably other benefits I haven’t identified yet.
Issue Analytics
- State:
- Created 4 years ago
- Comments:11 (4 by maintainers)

Top Related StackOverflow Question
@golavr I didn’t mean to cause offence or to diminish your effort, and I take your point. It was unfortunate that we worked on the same thing at the same time.
I’ve reopened your PR and I will try to merge it and redo my work as you suggest.
agree that ResultCommonLogic impose performance penalties. my take on this is that library should pay the maintainability discomfort in order to provide robust solution to users, even at the cost of violating the DRY principle.
regarding class vs struct after enabling C# 8 and nullable you still get warning new developers tend to ignore warnings
with a little effort… hitting the potential fix -> Decalre as nullable you unleashed the chaos