
Monads are not Rocket Surgery— Part Two: Result
In Part One of this article, we learned about the Maybe monad. Maybe made it easier for us to safely handle null references in a functional pipeline. In Part Two, we will take a look at how the Result monad in KivaKit captures and handles failure information in a pipeline.

Result
The Result class subclasses Maybe and adds methods relevant to capturing failure messages. All the methods in Maybe work as expected, and treat a failure condition as if it was a null reference. This allows functional pipelines to ignore failures in the same way that Maybe allows them to ignore null values.
If we reduce Result to the key methods, we see:
class Result<Value> extends Maybe<Value>
{
static <T> Result<T> success(T value) {} static <T> Result<T> failure(Throwable,
String message,
Object... arguments) {} static <T> Result<T> failure(String message,
Object... arguments) {} boolean succeeded() {}
boolean failed() {}
<Output, Mapper extends StringMapper<? extends Output>>
Maybe<Output> map(Class<Mapper> mapperType) {} MessageList messages() { } static <T> Result<T> capture(Broadcaster value) {}
static <T> Result<T> run(Broadcaster, Code<T>) {}
}

Success and Failure
Result objects can be constructed to represent the success or failure of an operation. A successful result is created like this:
var result = Result.success(user);
If we call succeeded() on this result object, it will return true. We can retrieve the result value with result.get().
Failure Result objects can be constructed like this:
var result = Result.failure("Unable to launch rocket!");
If we call failed(), it will return true, and messages() will contain a Problem object with the message “Unable to launch rocket!”.
String Conversions
The kivakit-converters mini-framework provides a variety of StringConverters. All StringConverters are StringMappers, so they can be applied with the convert(StringMapper) method. For example, this code:
Result.success("5 minutes")
.convert(DurationConverter.class)
.get();
converts the string “5 minutes” to a Duration object.
The Result class creates a DurationConverter, passing this as the sole argument to its constructor. This connects the converter to Result, so it can capture any failure messages during the conversion. If the conversion fails, the result will be absent.

Capturing the Result of an Operation
Now for the interesting part. If we call Result.capture(Broadcaster) the Result object we get back will capture any failure messages that the given broadcaster transmits. For example:
class Operation extends BaseComponent implements Code<String>
{
String run() { }
}var operation = new Operation();var result = Result.capture(operation);
operation.run();
return result;
If Operation.run() (which implements the Code interface) successfully returns a String, it will be captured in result, succeeded() will return true, and get() will return the value that was produce. If it fails by throwing an exception, or by broadcasting a Problem, the relevant failure message(s) will be contained in messages(), and failed() will return true.
We can do this all in one line as well:
return Result.run(operation, operation::run);

Conclusion
We learned in this article how to use the Result monad to represent a success or failure state. We can build function pipelines with Result that do not have to concern themselves with failures or null values. We can easily capture failures while executing code that can produce them.
Now we’re cooking with gas!
