C++ Logo

std-proposals

Advanced search

Re: Middle ground between "return" and exceptions?

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Mon, 14 Sep 2020 14:54:08 -0400
On Mon, Sep 14, 2020 at 2:44 PM Dmitry Dmitry via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> [...]
> If you wish, this new flavour can be viewed as a middle ground between (1)
> regular return's (which often requires boilerplate for handling the pattern
> above) and (2) exceptions (which are too non-local and implicit and can
> "jump" at an arbitrary place).
>
> The code above would look like this:
> std::optional<std::string> FindUsersCity() {
> std::optional<ContactsServer> contacts =
> GetOrOpenContactsServerConnection();
> std::optional<UserId> uid = contacts.
> *GetOrReturnNullOpt()*->GetUserId();
> std::optional<GeoServer> geo = GetOrOpenGeoServerConnection();
> std::optional<Location> uloc = geo.*GetOrReturnNullOpt()*
> ->GetLocation(*uid);
> return uloc.*GetOrReturnNullOpt()*->GetCityName();
> }
> where *GetOrReturnNullOpt()* is a method that (1) either returns a value
> if std::optional is not empty, (2) or returns from FindUsersCity() if
> std::optional is empty.
>

Nobody would ever add that method to `std::optional`, because it's much too
specific in terms of what it does. (And uses the wrong capitalization
convention. ;D)
However, what you want is already possible in Standard C++:

std::optional<std::string> FindUsersCity() {
    try {
        std::optional<ContactsServer> contacts =
GetOrOpenContactsServerConnection();
        std::optional<UserId> uid = contacts.value().GetUserId(); // throw
bad_optional_access on empty
        std::optional<GeoServer> geo = GetOrOpenGeoServerConnection();
        std::optional<Location> uloc =
geo.value().GetLocation(uid.value()); // throw bad_optional_access on empty
        return uloc.value().GetCityName();
    } catch (const std::bad_optional_access&) {
        return std::nullopt;
    }
}

The only problem with this is that it's remotely possible
that GetOrOpenContactsServerConnection() might itself throw
std::bad_optional_access and we've decided that we want to propagate that
exception out of FindUsersCity() instead of turning it into a nullopt. We
just hope we don't write such convoluted code.

This is nice and general because you can put *anything* in the
catch-clause, not just "return std::nullopt".

Compilers don't optimize this code well today, but at least everyone's well
aware that they *really ought to*. There are lots of papers and blog posts
and such on the "abstraction penalty" for exception-handling code.

–Arthur

Received on 2020-09-14 13:54:22