[...]
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