Mongrel Monads, Dirty, Dirty, Dirty

By Niall Douglas

Are you using enums to return error states from functions (or even an int or bool!)? Do you find writing exception safe C++ a poor return on coding investment, and end up avoiding using most of the STL entirely because it could throw exceptions in all sorts of unhelpful places? Have you ever wondered what on earth the C++ 11’s <system_error> header is actually useful for?

One might think that after thirty years C++ would have decided upon a canonical way of handling errors, but it is very clear the jury remains out with heavy fragmentation in the C++ user base as to how best to handle errors. The new systems programming languages Rust and Swift have chosen a canonical error handling system based on immediate stack unwinding returns of integer error codes in a monadic wrapper e.g. Rust’s Result<T> and Option<T>. Efforts are underway to standardise something similar for C++ with optional<T> and soon WG21 LEWG’s expected<T, E> which recently lost its monadic operations as it gets pared ever further down to its essentials for standardisation.

This talk reviews these four standardised error handling techniques in C++, and how well the three major compilers and library implementations implement these techniques into overhead. I will also be introducing for the first time my own solution to this problem called outcomes (implemented by a proposed Boost.Outcome library) which implement a very impure and dirty - but very lightweight on compile and runtime overhead – simple “mongrel monad” outcome<T>, result<T> and option<T> transport factory specifically targeted at extending C++ 11’s std::exception_ptr and std::error_code in a more convenient to use form, thus providing a unified lossless error handling system for C++. I am hoping these will eventually form part of SG14 (games/low latency)’s recommendations for maximum performance C++ as a lighter weight and more convenient to use for error handling alternative to the LEWG expected<T, E>.