An exception that represents an error value.
Creates an Expected object from an expected value, with type inference.
Creates an Expected object from an error value, with type inference.
Default hook implementation for Expected
Expected!(T, E) is a type that represents either success or failure.
Hook implementation that throws exceptions instead of default assert behavior.
Constructs Expected from the result of the provided function.
Template to determine if hook provides function called on empty error.
Template to determine if hook provides function called on empty value.
Template to determine if hook provides custom handler for case when the Expected result is not checked.
Template to determine if hook enables or disables copy constructor.
Template to determine if provided Hook enables default constructor for Expected
Applies a function to the expected value in an Expected object.
Applies a function to the expected error in an Expected object.
Maps a Expected<T, E> to U by applying a function to a contained value, or a fallback function to a contained error value.
Basic usage
auto foo(int i) { if (i == 0) return unexpected!int("oops"); return expected(42 / i); } auto bar(int i) { if (i == 0) throw new Exception("err"); return i-1; } // basic checks assert(foo(2)); assert(foo(2).hasValue); assert(!foo(2).hasError); assert(foo(2).value == 21); assert(!foo(0)); assert(!foo(0).hasValue); assert(foo(0).hasError); assert(foo(0).error == "oops"); // void result assert(Expected!(void)()); // no error -> success assert(!Expected!(void)().hasError); // assert(unexpected("foo").value); // doesn't have hasValue and value properties // expected from throwing function assert(expected!bar(1) == 0); assert(expected!bar(0).error.msg == "err"); // orElse assert(foo(2).orElse!(() => 0) == 21); assert(foo(0).orElse(100) == 100); // andThen assert(foo(2).andThen(foo(6)) == 7); assert(foo(0).andThen(foo(6)).error == "oops"); // map assert(foo(2).map!(a => a*2).map!(a => a - 2) == 40); assert(foo(0).map!(a => a*2).map!(a => a - 2).error == "oops"); // mapError assert(foo(0).mapError!(e => "OOPS").error == "OOPS"); assert(foo(2).mapError!(e => "OOPS") == 21); // mapOrElse assert(foo(2).mapOrElse!(v => v*2, e => 0) == 42); assert(foo(0).mapOrElse!(v => v*2, e => 0) == 0);
BSL-1.0
This module is implementing the Expected idiom.
See the Andrei Alexandrescu’s talk (Systematic Error Handling in C++ and its slides.
Or more recent "Expect the Expected" by Andrei Alexandrescu for further background.
It is also inspired by C++'s proposed std::expected and Rust's Result.
Similar work is expectations by Paul Backus.
Main differences with that are:
Default type for error is string, i.e. Expected!int is the same as Expected!(int, string)
Expected has customizable behavior with the help of a third type parameter, Hook. Depending on what methods Hook defines, core operations on the Expected may be verified or completely redefined. If Hook defines no method at all and carries no state, there is no change in default behavior. This module provides a few predefined hooks (below) that add useful behavior to Expected:
The hook's members are looked up statically in a Design by Introspection manner and are all optional. The table below illustrates the members that a hook type may define and their influence over the behavior of the Checked type using it. In the table, hook is an alias for Hook if the type Hook does not introduce any state, or an object of type Hook otherwise.