Boost logo

Boost :

Subject: Re: [boost] [err] RFC
From: Domagoj Šarić (dsaritz_at_[hidden])
Date: 2015-11-29 22:18:19


On Fri, 27 Nov 2015 04:56:32 +0530, Gavin Lambert <gavinl_at_[hidden]>
wrote:
> I was referring to the hypothetical combiner function that accepted
> multiple fallible_result<>&& parameters (since it consumes all of them),
> and then returns its own fallible_result from one or more of them.
>
> Within the function it will not be able to call any methods on the
> fallible_result<>&& parameters (since they're actually lvalues now),
> except for one very common case:
> auto a = std::move(paramA).as_result_or_error();
>
> (And that this construct is not unreasonable as long as paramA is not
> accessed after this point -- it's no different from any other move.)

Since std::move is meant for, well, moving and not for accessing special
functionality (at least in client code) I would consider this
'smelly'/unreasonable/'antipatternistic'...regardless of that, even if you
do do this everything will still work (with the recently discussed
changes) although with possibly slight codegen degeneration.

> I was also referring to the compiler errors that would be generated from
> "improper use" being the same ones that people are likely to reflexively
> add std::move() calls to resolve.

Well that would mean that 'people' didn't 'RTM' i.e. they don't know what
both fallible_result and std::move are for...
You could just as well argue that you can circumvent RAII with placement
new...the point is that you cannot unintentionally do the wrong thing...

> The woe is that you'd also get a runtime assert since two
> fallible_results managed to exist at the same time again. But yes, that
> could only happen if you forgot to actually use them, or if you thought
> the errors meant that you were supposed to add std::move().

As above...

> It does make the behaviour a little strange for the various cases though:
>
> calcA(); // throws because fallible_result went uninspected
> calcB();

That's intended/by design behaviour, 'the classic EH style usage' (the
throw happens only if the call failed, i.e. the return value contains an
err_t, not T, so the err_t is thrown, with a possible transformation into
an object/wrapper more apt for EH but those are details I'd rather not go
at this stage)...what problem do you see here?

ps. if the functions in question would otherwise return void (and would
thus be transformed to return fallible_result<void, err_t>) these will be
handled by a partial specialisation (for void) that would not contain
was-examined asserts...

> --------------
> auto a = calcA();
> auto b = calcB(); // asserts because two fallible_results exist
> // compiler error if a or b are used later without std::move

Again, intended behaviour - error on wrong usage (as there is no way for
the compiler and/or library to deduce whether you want the auto to mean T
or result_or_error<T, err_t>) - with the difference that multiple
fallible_results are/will no longer be an error (just that at least one is
inspected before leaving the scope)...

> --------------
> foo_error_t a = calcA();
> foo_error_t b = calcB();
> // no errors even if a or b go unused after this point
> // a & b are either valid or have error codes

Intended behaviour - error 'code' style - this is kind of like a
generalised concept of the std::pair<iterator, bool> returning
std::map::insert() overload...
...might be improved to also require (assert) that at least one
result_or_error is inspected before leaving the function

> --------------
> foo_t a = calcA(); // throws if calcA has an error
> foo_t b = calcB(); // throws if calcB has an error
> // a & b are both valid if you survive this far

Same/similar to your first example - intended behaviour - EH style...

> --------------
> auto a = calcA().as_result_or_error();
> auto b = calcB().as_result_or_error();
> // no errors even if a or b go unused after this point
> // a & b are either valid or have error codes

> --------------
> something(calcA(), calcB()); // asserts for two fallible_results

No longer, we fixed those, no? ;)

> --------------
> something(calcA().as_result_or_error(),
> calcB().as_result_or_error());
> // might work or might assert depending on the compiler's mood

Same as above (fixed).
(note: the as_result_or_error verbosity is only required if something() is
a function template so implicit conversion does not kick in)

-- 
"What Huxley teaches is that in the age of advanced technology, spiritual
devastation is more likely to come from an enemy with a smiling face than
     from one whose countenance exudes suspicion and hate."
Neil Postman
---
Ova e-pošta je provjerena na viruse Avast protuvirusnim programom.
https://www.avast.com/antivirus

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