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