Boost logo

Boost :

Subject: Re: [boost] [outcome] High level summary of review feedback accepted so far
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2017-05-29 15:30:14

On 29/05/2017 08:23, Gavin Lambert via Boost wrote:
> On 28/05/2017 10:46, Niall Douglas wrote:
>>>> I would agree. But well, we were outvoted. And that probably means
>>>> rejection of this library, as the presented library does not implement
>>>> what the majority want (yet).
> Just to clarify the meaning, since I'm not especially fluent in
> standardese: by "narrow contract" you mean "has UB if you don't include
> external checks", correct? I really don't like that even being an
> option in a type intended to improve error handling.

If you feel this way too, I think between me, you and Peter we now are
equal in number with the other group.

Of course it's not about numbers of votes, but about feeling out where
the majority opinion is at.

>> I personally think I'll have very little use for the narrow contract
>> varieties, but I've been convinced by the non-empty-capable vs
>> empty-capable distinction because it means that my public API functions
>> can specify via the type they return whether an empty return is possible
>> or not, thus more accurately specifying their public contract. That, and
>> the fact I can still use a receiving empty-capable variety for detecting
>> when loops haven't found what they were looking for etc I find very
>> compelling.
> Doesn't that make things more complicated, though? Library A uses one
> flavour of it and library B uses a different flavour; how do they
> interoperate? (I know both can coexist due to namespacing and other
> things, but still if one method calls the other there has to be some
> kind of handover of the return value.)

Outcome implements well defined directional implicit conversion between
flavours. It does now, and would continue to do so.

> For that matter, what happens when a method in library A (using the
> guaranteed-never-empty flavour) calls a method in library B (using the
> empty-by-default flavour)? Can they put the return value into one of
> their never-empty outcomes (but then what if it's empty?) or do they
> have to work with the might-be-empty outcome type that's foreign to
> their own code and way they want to do things, and thus more likely to
> be used incorrectly?

Under what I said I would do in the high level summary, the programmer
would need to manually unpack the empty-capable object, deal with the
empty state if present, and construct an non-empty-capable object for
return. No implicit nor explicit conversion exists between empty-capable
and non-empty-capable.

> Typedefs can sort out the differences to a certain extent, but then you
> need to remember to use the right one with each library (either getting
> unexpected behaviour or the compiler yelling at you when incorrect,
> depending on implementation, neither of which is particularly
> desirable), and there's possible interoperability issues for storing the
> results from multiple libraries into a single vector, for example.

I believe I have been persuaded to drop the checked_* separate types in
favour of unchecked, but longer named, new member functions.

I'll be posting a v2 high level summary later today.

I don't think accumulating disparate typed results into a vector is a
problem - just use the most representative type possible. Outcome
deliberately implements a hierarchy of types with a most representative
edition at the bottom. It can always accumulate anything from any less
representative sibling type. I use this behaviour extensively in my own

> What about interop between a v1 outcome and a v2 outcome? That's no
> longer an identical implementation.

My current intention is that the programmer would need to unpack and
pack at such a boundary. Safest, until we know more.


ned Productions Limited Consulting

Boost list run by bdawes at, gregod at, cpdaniel at, john at