# Poor man's Result<T,E> implementation

Moritz Maxeiner via Digitalmars-d digitalmars-d at puremagic.com
Fri Mar 3 17:45:17 PST 2017

```Having taken a bit of time to get more familiar with Rust I
wondered if we could have something like Rust's algebraic result
type[1] using Phobos' Algebraic template and started to
experiment:

--- Usage
enum DivisionError
{
ZeroDivisor
}

Result!(int, DivisionError) divide(int dividend, int divisor)
{
mixin Result;
if (divisor == 0) { return err(DivisionError.ZeroDivisor); }
return ok(dividend / divisor);
}

// If you statically know that in your specific case the error
cannot
// happen you can just unwrap the Result to the contained
successful value
int valid = divide(15, 3).unwrap();
// This will throw an instance of Error, since unwrapping a Result
// that you cannot guarantee to actually be Ok is a logic bug.
int invalid = divide(15, 0).unwrap();

// Do some calculations of which some may fail
auto input = [ tuple( 15, 3),
tuple( -3, 0),
tuple(  3, 7)];
auto results = input.map!(i => divide(i.expand));

// Use case 1: Silently ignore failed calculations
results.save
.filter!(r => r.type == typeid(Ok!int))
.each!(tryVisit!(
(Ok!int result) => writeln(result),
() {}
));

// Use case 2: "Handle" them
results.save
.each!(Visit!(
(Ok!int result) => writeln(result),
(Err!DivisionError err) => writeln("Failed to divide: ", err)
));
---

--- Implementation
struct Ok(T) {
T v;
alias v this;
string toString() { return v.to!string; }
}

struct Err(E) {
E e;
alias e this;
string toString() { return e.to!string; }
}

alias Result(T, E) = Algebraic!(Ok!T, Err!E);

mixin template Result()
{
alias R = typeof(return);
alias T = typeof(__traits(getMember, R.AllowedTypes[0], "v"));
alias E = typeof(__traits(getMember, R.AllowedTypes[1], "e"));

R ok(T v) { return cast(R) Ok!T(v); }
R err(E e) { return cast(R) Err!E(e); }
}

@trusted nothrow
auto unwrap(R)(R r)
{
try {
return cast(typeof(__traits(getMember, R.AllowedTypes[0],
"v")))
r.get!(R.AllowedTypes[0])();
} catch (VariantException) {
throw new Error("Attempted to unwrap error");
} catch (Exception) {
// VariantN.get is supposed to only throw
VariantException. Bug?
assert(false);
}
}

import std.variant;
import std.conv;
import std.typecons;
import std.algorithm;
---

[1] https://doc.rust-lang.org/std/result/enum.Result.html
```