Boost logo

Boost :

Subject: Re: [boost] [review] Review of Outcome v2 (Fri-19-Jan to Sun-28-Jan, 2018)
From: Vinícius dos Santos Oliveira (vini.ipsmaker_at_[hidden])
Date: 2018-01-27 13:33:38


2018-01-27 0:31 GMT-03:00 Emil Dotchevski via Boost <boost_at_[hidden]>:

> Question: if using the OUTCOME_TRY macro is equivalent to calling the
> function, checking for error and then returning an error if there is an
> error, how is this different from using exceptions? Semantically, exception
> handling does nothing more than check for errors and returning errors if
> there were errors

There is a single control flow to analyse: the return of the function. You
don't need a "parallel" control flow construct to check for error case.

This simplification just adds up:

   - You can't forget to check the error case (it's part of the type
   system).
   - It's self-documenting.
   - There are no strange interactions between Outcome and the rest of the
   language (e.g. throwing destructors, transporting exception between
   threads, and so on...).
   - Add templates to the mix and you'll remember who is responsible for
   non-insignificant amount of rules and added code boilerplate.
   - ...

OUTCOME_TRY is just convenience. It mirrors the Rust's try macro:
https://doc.rust-lang.org/1.9.0/std/macro.try!.html

Rust has sum types and pattern matching at language level from day 0 (day 0
is Rust 1.0). The rest of the features were thought (or revised) with
pattern matching in mind before 1.0 release. It has conveniences that C++
will never have (Rust /lacks/ constructors that can throw, moves that can
throw and moved objects that will call a destructor). Rust doesn't have
exceptions and nobody misses them.

On the level of what C++ could have, Rust has monadic operations.

with much more readable syntax:
>
> return parse(read_data(open_file(path)));

Check OUTCOME_TRYX

Of course it'd be more verbose:

return parse(OUTCOME_TRYX(read_data(OUTCOME_TRYX(open_file(path)))));

To the point of being ridiculous. Here it'd be better to split it in one
line per call.

In Rust, try! macro is only 4 letters long. Also, it was "promoted" to an
operator: https://m4rw3r.github.io/rust-questionmark-operator

With monadic operations, we could turn the above code into something like:

return open_file(path).and_then(read_data).and_then(parse);

But this assumes all operations return the same error type (e.g.
std::error_code). This should be true at least to the I/O functions
(open_file and read_data). Maybe we could use something like
std::common_type or another magic detection to relax the requirements (i.e.
it must be the same error type) a bit (it'd diverge from other
implementations, but we have this freedom).

-- 
Vinícius dos Santos Oliveira
https://vinipsmaker.github.io/

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk