Is there a better way for this "idiom"?
if(State s = loadSomething()) { } else return s;
In other words, I want to do something, which may return an error (with a message) or a success state, and if there was an error I want to return it. This can become very repetitive, so I want to shorten it. For example
if(State s = loadFoobar(&loadPointer, &results)) { } else return s;
if(State s = loadBaz(&loadPointer, &results)) { } else return s;
if(State s = loadBuz(&loadPointer, &results)) { } else return s;
This must not use exceptions which I would favor otherwise (unsuitable for this build). I could write up a little class BooleanNegator<State>
that stores the value, and negates its boolean evaluation. But I want to avoid doing this ad-hoc, and prefer a boost/standard solution.
You could do:
for (State s = loadSomething(); !s; ) return s;
but I am not sure if it is more elegant, and it is definitely less readable...
I assume the context is something like
State SomeFunction()
{
if(State s = loadSomething()) { } else return s;
return do_something_else();
}
without throwing exceptions where do_something_else()
does something of relevance to SomeFunction()
and returns a State
. Either way, the result of continuing within the function needs to result in a State
being returned, as falling off the end will cause the caller to exhibit undefined behaviour.
In that case, I would simply restructure the function to
State SomeFunction()
{
if (State s = loadSomething())
return do_something_else();
else
return s;
}
Implicit assumptions are that State
has some operator (e.g. operator bool()
) that can be tested, that copying a State
is possible (implied by the existence of a loadSomething()
that returns one) and relatively inexpensive, and that two instances of State
can exist at one time.
Aside from some smart/hacky uses of different keywords to get the same behavior, or adding more-or-less complex extra templates or macros to get unless()
keyword or to somehow manage to inject !
operator, I'd stick to just the basic things.
This is one of the places I'd (probably) inject extra "unnecessary" brackets:
void someFunction()
{
// some other code
{ State s = loadSomething(); if(!s) return s; }
// some other code
}
However, in this exact case, I'd expand it to emphasise the return
keyword, which can be easily overlooked when it's squashed to a one-liner. So, unless the one-liner is repeated many times and unless it's clear&obvious that there's a return
inside, I'd probably write:
void someFunction()
{
// some other code
{
State s = loadSomething();
if(!s)
return s;
}
// some other code
}
It might look like elevating the scope of the s
, but actually it is equivalent to declaring State s
in if()
. All thanks to the extra brackets which explicitly limit the visibility of local s
.
However, some people just "hate" seeing { .. }
not coupled with a keyword/class/function/etc, or even consider it to be unreadable due to "suggesting that a if/while/etc keyword was accidentally deleted".
One more idea came to me after you added the repetitive example. You could have tried a trick known from scripting languages where &&
and ||
may return a non-bool values:
State s = loadFoobar(&loadPointer, &results);
s = s || loadBaz(&loadPointer, &results);
s = s || loadBuz(&loadPointer, &results);
if(!s) return s;
however there's a problem: in contrast to script languages, in C++ such overloads of &&
and ||
lose their short-circuit semantics which makes this attempt pointless.
However, as dyp pointed out the obvious thing, once the s
scope is elevated, now simple if
can be introduced back. Its visibility can be limited back again with extra {}
:
{
State s;
if(!(s = loadFoobar(&loadPointer, &results))) return s;
if(!(s = loadBaz(&loadPointer, &results))) return s;
if(!(s = loadBuz(&loadPointer, &results))) return s;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With