In use
This is how you might now write application code using these three libraries:
namespace app
{
// A markup function to indicate when we are ValueOrError converting
template <class T> inline outcome<typename T::value_type> ext(T &&v)
{ //
return outcome<typename T::value_type>(std::move(v));
}
outcome<void> go() // NOT noexcept, this can throw STL exceptions e.g. bad_alloc
{
// Note that explicit construction is required when converting between differing types
// of outcome and result. This makes it explicit what you intend to do as conversion
// may be a lot more expensive than moves.
// Try to GET this URL. If an unsuccessful HTTP status is returned, serialise a string
// containing a description of the HTTP status code and the URL which failed, storing
// that into a httplib_error exception type which is stored as an exception ptr. The
// TRY operation below will return that exception ptr to be rethrown in the caller.
// Otherwise the fetched data is returned in a std::string data.
OUTCOME_TRY(auto data, ext(httplib::get("http://www.nedproductions.biz/")));
string_view data_view(data);
// HTML tidy the fetched data. If the C library fails due to an error corresponding to
// a standard library exception type, throw that. Otherwise, synthesise an exception
// ptr of type tidylib_error which stores the error code returned in an error code with
// generic category (i.e. errno domain).
// TRY operation below will return that exception ptr to be rethrown in the caller.
// Otherwise the tidied data is returned into holdmem, with the string view updated to
// point at the tidied data.
OUTCOME_TRY(auto holdmem, ext(tidy_html(data_view)));
// Write the tidied data to some file. If the write fails, synthesise a filesystem_error
// exception ptr exactly as if one called filelib::write_file(data_view).value().
OUTCOME_TRY(auto written, ext(filelib::write_file(data_view)));
return success();
}
} // namespace app
The curiosity will be surely the ext()
markup function, which needs
explaining. It was felt
important during Outcome’s design that value_or_error
conversions never
be implicit, as they almost always represent a transition across an
ABI or semantic boundary. They are also usually non-trivial to implement
and compile, and it was felt important that the programmer ought to
always mark the semantic boundary transition at the point of every use,
as considerable amounts of code may execute.
How the end user chooses to mark up their code is up to them, however
above we use a simple ext()
function to mark up that the function
being called is external to the application. This ticks our box of
requiring the documentation, at the point of use, of every transition
in failure handling boundaries.
Note that we are able to use TRY
as normal throughout this function.
Everything “just works”.
And most especially note that we never, at any stage, needed to modify
the source code of httplib
, tidylib
nor filelib
, nor inject
custom things into their namespaces. This entire worked example was
achieved solely by app
based customisation points, and via convert
.