# Avoiding Result Pitfalls

Sadly, C# does not ship with a `Result<T>` as part of the BCL. Even sadder, our friends lucky enough to work in F# have a really good one, so the .NET IL is clearly capable of it.

This hasn't prevented many an ambitious programmer from attempting to write their own `Result<T>` type, and why wouldn't you? Exceptions are unexpected, and expensive. A type that communicates to the programmer that failure is a possibility and that they should be prepared to handle it will only ensure good coding practices, right? Sadly, this isn't always the case.

Many codebases end up littered with `Result<T>` types *and* throw many exceptions. The object causes friction and is most often ignored. This leaves developers with a bad taste in their mouth about the `Result<T>` type. Some of this is avoidable, and some of this, sadly represents a shortcoming in the C# language itself.

By understanding where developers go wrong, and where they language falls short, we can create a more robust `Result<T>` type that stands a much better chance of justifying the additional complexity.

## Where C# Falls Short: No Safe Unwrap

Some languages, like Rust, provide an elegant way to unwrap `Result<T>` types. In the case of Rust, the `?` operator will unwrap a `Result<T>` and return the value. If the `Result<T>` represents an error, the function immediately early returns the error. Thus, any function that uses the `?` operator in Rust, must itself return a `Result<T>` type.

```rust
fn read_file_contents(filename: &str) -> Result<String, io::Error>
{
	// Open the file, using `?` to propagate errors
	let mut file = File::open(filename)?;
	
	let mut contents = String::new();
	// Read the file contents into a string, using `?` to propagate errors
	file.read_to_string(&mut contents)?;
	Ok(contents) 
}
```

This will feel very familiar to C# developers who have a similar unwrap mechanic for `Task<T>`: async/await. the `await` keyword unwraps a task, and any function which uses `await` must be marked `async` and itself, return a task.

```csharp
public async Task<string[]> ReadFileContents(string path)
{
	// read all lines using `await` to unwrap an asynchronus function
	var lines = await File.ReadAllLinesAsync(path);
	return lines;
}
```

Because a `Result<T>` type is not part of the BCL, there's no reason (or good way really) to add a similar operator to unwrap a `Result<T>` in C# and propagate any errors. Sadly, the following is not valid C#

```csharp
public Result<string> GetUsername(Guid userId)
{
	// use `?` to propogate errors
	var user = _db.Find<User>(userId)?
	return user.Name;
}
```

## Where Developers Go Wrong: The Unsafe Unwrap

In an effort to make their `Result<T>` types easier to use, many developers will add an unsafe unwrap. Usually this takes the form a property called `Value` which simply throws if the `Result<T>` represents a failure. The following examples for the rest of this article are using C# 12 with nullable enabled, and all warnings treated as errors.

```csharp
// A simple Result<T> with an unsafe unwrap called `Value`
public class Result<T>
{
	private readonly T? _value;
	private readonly Exception? _exception;
	private Result(T? value, Exception? exception)
	=> (_value, _exception) = (value, exception);

	public static Result<T> Success(T value) => new(value, exception: null);
	public static Result<T> Failure(Exception ex) => new(value: null, ex);

	// The unsafe unwrap
	public T Value => _value ?? throw ex;
}
```

If the option to simply "get the value out" of a `Result<T>` is there, developers will take it. They will take it and the code will work, until one day it doesn't. The entire reason for switching to a `Result<T>` type is lost. You're carefully wrapping return values in a type that prepares for failure, only for the calling code to assume success anyway.

## What can we do?

Understanding the language shortfalls, and the pitfalls of an unsafe unwrap, is it possible to make a `Result<T>` worth using in C#? That answer to that will always be subjective, but I believe we can do better than the example above.

### Match/Switch Functions

How do you best get the value out of a `Result<T>`? One way is to flip the question, or "How do you best inject behavior *into* a `Result<T>`" By providing Match/Switch functions we can require that calling code provide a path forward in both the case of a success or a failure. Here is an implementation of this, and an example of its usage

```csharp
public record Error(string Message);

public class Result<T>
{
	private readonly T? _value;
	private readonly Error? _error;
	
	private Result(T? value, Error error)
	=> (_value, _error) = (value, error);

	public static Result<T> Success(T value) => new(value, null);
	public static Result<T> Failure(Error error) => new(null, error);
  
	public TOut Switch<TOut>(
	  Func<T, TOut> success,
	  Func<Error, TOut> error)
	=> _value is not null
		? success(_value)
		: error(_error!);
}

// Usage
Result<User> userResult = GetUser(userId);
string userName = userResult.Switch(
	success: user => user.Name,
	error: err => $"Unable to find user: {err.Message}");

return userName;
```

This doesn't have an unsafe unwrap, but it can be a little awkward in an imperative codebase, which describes quite a bit of C# code. To address this, we can rely on subclasses and pattern matching

## Subtypes and Pattern Matching

C# pattern matching provides a powerful and straight forward way to ask about the runtime type of an object and capture a typed reference to that object. This makes it easy for use to check for a successful `Result<T>` with a simple `if` statement and use the successful value in a compile checked way.

```csharp
public record Error(string Message);
public abstract class Result<T>
{
	public static Result<T> Success(T value) => new Success(value);
	public static Result<T> Failure(Error error) => new Failure(error);
}

public class Success<T> : Result<T>
{
    public T Value { get; }
    internal Success(T value) => Value = value;
}
public record Failure<T> : Result<T>
{
    public Error Error { get; }
    internal Failure(Error error) => Error = error;
}

// Usage
Result<User> userResult = GetUser(userId);
if (userResult is Success<User> success)
{
	return success.Value.Name;
}
```

Unfortunately, there isn't a great way to tell the compiler that if a `Result<T>` instance isn't a `Success<T>` type, then it *must* be a `Failure<T>` type. The lack of discriminated unions is why we're in this pickle to begin with. Still however, we can press on and refine this type further

### Implicit operators

We can clean up our static factory methods with implicit conversions, this if a function's return type is `Result<T>` we can simply return a `T` or an `Error`

```csharp
public abstract class Result<T>
{
	public static implicit operator Result<T>(T value)
    => new Success(value);

	public static implicit operator Result<T>(Error error)
    => new Failure(error);
}

// Usage
public static Result<decimal> Divide(decimal numerator, decimal denominator)
{
	if (denominator == 0) return new Error("Cannot divide by zero");
	return numerator / denominator;
}
```

### Adding a Safe Unwrap

Next let's try and add a safe unwrap (or at least to most elegant one that C# will let us) We want failure to be the `true` condition so we can early return the error. We'll use the nullable branch analysis to indicate to the client code when out parameters are or are not null.

```csharp
public abstract class Result<T>
{
    // Omitted

    public abstract bool UnwrapFailed(
        [NotNullWhen(true)]
        out Error? error,
        [NotNullWhen(false)]
        out T? value);
}


public class Success<T> : Result<T>
{
    public override bool UnwrapFailed(
        [NotNullWhen(true)]
        out Error? error,
        [NotNullWhen(false)]
        out T? value)
    {
        error = null;
        value = Value;
        return false;
    }
}
public record Failure<T> : Result<T>
{
    public override bool UnwrapFailed(
        [NotNullWhen(true)]
        out Error? error,
        [NotNullWhen(false)]
        out T? value)
    {
        error = Error;
        value = null;
        return true;
    }
}

// Usage
public Result<string> AssembleGreeting(Guid greetingId, Guid nameId)
{
    Result<string> greetingResult = LoadGreeting(greetingId);
    Result<string> nameResult = LoadName(nameId);

    if (greetingResult.UnwrapFailed(out var error, out var greeting))
        return error; // error is not null here
    if (nameReuslt.UnwrapFailed(out error, out var name))
        return error // error is not null here

    // neither greeting or name are null here
    return $"{greeting}, {name}!";
}
```

### Conclusion

C# is a high ceremony language, and there are limits to how succinctly we can express certain concepts and structures that come naturally to other languages like Rust or F#, but with this in mind we can still craft a result that achieves its goal: forcing the calling code to deal with any potential errors at compile time.

Here are some fun exercises when crafting your own result types:

* Add a map/select function
    
* Extend the map/select function to automatically flatten (`Result<Result<T>>` becomes `Result<T>`)
    
* Add a way for a `Result<Task<T>>` to be `awaited` returning `Result<T>`
    
* Add an equality operator which respects referential transparency
    
    * Two `Result<int>` objects which both contain the same number should be equal
        
    * A `Result<int>` which is a `Success<int>` that holds `5` should be equal to an `int` which holds `5`
