I often write code that ends with long sequences like
int error; error = do_something(); if (error) { return error; } error = do_something_else(with, some, args); if (error) { return error; } error = do_something_yet_again(); if (error) { return error; } return 0;
I am looking for a cleaner way to write this, to some extent avoid repeated identical checks. So far I have written the macro ERROR_OR , which works like
#define ERROR_OR(origerr, newerr) \ ({ \ int __error_or_origerr = (origerr); \ (__error_or_origerr != 0) \ ? __error_or_origerr \ : (newerr); \ })
which allows the source code to become something like
int error = 0; error = ERROR_OR(error, do_something()); error = ERROR_OR(error, do_something_else(with, some, args)); error = ERROR_OR(error, do_something_yet_again()); return error;
This (in my opinion) is a little cleaner. This is also less clear, since the macro function ERROR_PRESERVE not obvious unless you read its documentation and / or implementation. It also does not solve the problem of repetition, it simply simplifies the recording of all (now implicit) checks in one line.
That I really would like to rewrite all this as it would be:
return ERROR_SHORT_CIRCUIT( do_something(), do_something_else(with, some, args), do_something_yet_again() );
The hypothetical macro ERROR_SHORT_CIRCUIT will be
- Take a variable number of expressions in an argument list
- Rate each expression in order
- If each expression evaluates to zero, first evaluate its value
- If any expression evaluates to nonzero, terminate immediately and evaluate the value of this last expression
The last condition is that my short circuit diverges from the direct use of the || because it will be evaluated at 1 instead of the error value.
My initial attempt to spell this:
#define ERROR_SHORT_CIRCUIT(firsterr, ...) \ ({ \ int __error_ss_firsterr = (firsterr); \ (__error_ss_firsterr != ERROR_NONE) \ ? __error_ss_firsterr \ : ERROR_SHORT_CIRCUIT(__VA_ARGS__); \ })
This has two obvious problems:
- It does not handle its base register (when
__VA_ARGS__ is the only value) - C does not support recursive macros
I looked through a few recursive hacks macros , but I donβt like to use this degree of preprocessing magic - there is too much space for something wrong. I also considered using real (possibly variational) functions, but that would require
- short circuit failure behavior
- passing functions as pointers and therefore normalizing their signatures
and both of them seem worse than the original, explicit code.
I am interested in hearing tips on the best way to handle this. I am open to different approaches, but my ultimate goal is to avoid repetition without compromising readability.
(I think itβs obvious that I envy the behavior of the || operator in languages ββlike Ruby).