question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal to make Result a class instead of a struct

See original GitHub issue

Result 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.

  1. 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> to Result<T> / Result actually call ToString() on the E error 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.

  2. The logic for creating Results is encapsulated in a special class ResultCommonLogic, an instance of which is then stored on every Result. This adds complexity and overhead. In spite of this, there is inevitably still plenty of code duplication.

  3. Issue #125 highlights the requirement for a non-value Result with a custom error type, something that would add yet another struct to the mix, whereas a base class might be a more fitting solution.

  4. 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:closed
  • Created 4 years ago
  • Comments:11 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
space-aliencommented, Sep 16, 2019

@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.

1reaction
golavrcommented, Sep 11, 2019

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

image

with a little effort… hitting the potential fix -> Decalre as nullable you unleashed the chaos

image

Read more comments on GitHub >

github_iconTop Results From Across the Web

Proposing a struct syntax for Python
So, I want some syntax to make create data-only classes extremely easy. Goals. I want syntax that will keep people from using collections....
Read more >
C#, struct vs class, faster? [duplicate]
Structs are to be used only for relatively small structures that should have value-like behaviour. Class and struct differences ...
Read more >
Why does Apple recommend to use structs by default?
Interesting, but I don't understand how that would be different from using class instead. Apart from that structs have their limitations ...
Read more >
Record structs - C# 10.0 draft feature specifications
Record struct types are value types, like other struct types. They implicitly inherit from the class System.ValueType .
Read more >
Proposal for dynamic implementation of interface - Go Forum
I want to discuss a proposal for adding the following reflection feature to Go. Given any Go interface type, instantiate a Go value...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found