tags:

views:

361

answers:

16

I have a function definition, where i call multiple functions. Even if one of the function fails i need to go ahead and call the rest of the functions and finally return a single error saying whether any of the function call failed. The approach which i had followed was

int function foo()

{


    int res, res1, res2, res3;

    res1 = function1();
    res2 = function2();
    res3 = function3();

    if (res1 == -1 || res2 == -1 || res3 == -1)
    {
         res = -1;
    }

    return res;
}

The possible another approach is

int function foo()

{


   int res;

   if (function1() == -1)
   {
        res = -1;
   }

   if (function2() == -1)
   {
        res = -1;
   }

   if (function3() == -1)
   {
       res = -1;
   } 

   return res;
}

Which is a better approach? Thanks in advance.

+2  A: 

What about:

int foo ()
{
    bool failed = false;
    failed |= (function1() != 0);
    failed |= (function2() != 0);
    failed |= (function3() != 0);
    return failed? -1 : 0;
}

You could also collapse the three calls into a single expression and omit the failed variable altogether (at the expense of readability):

int foo ()
{
    return ((function1() != 0) | (function2() !=0 ) | (function3() != 0))? -1 : 0;
}

I like the first approach when function1 function2 and function3 have the same signature because I can put them in a function pointer table and loop over the entries, which makes adding function4 alot easier.

André Caron
Your second approach won't work - it isn't guaranteed to call all the functions. Your first approach will work but seems a bit complicated for such a simple operation.
Dakota Hawkins
You're right. I changed it for bitwise `|` instead of logical `||` just as in another proposed solution so that it always evaluates all the functions now.
André Caron
@Andre: And now it suffers from the arbitrary call order problem that also exists in Jack's answer, as pointed out by John Marshall.
Ben Voigt
I prefer the first form in any case. The effect, as well as the order are more clearly conveyed. Moreover, a single temporary is used and a single check is done at the end, achieving the best of both of the forms the poster proposed.
André Caron
+8  A: 

No difference at all, both will be optimized to same machine code. Preference, maintainability, and that depends on team guidelines, preferences.

Madman
The compiler's optimizations are restricted in ways yours are not by the language's semantics and worst-case assumptions. I very strongly doubt both approaches will end up producing the same machine code: the first approach requires short-circuit evaluation and only updates `res` at most once; the second approach sets `res` up to 3 times and tests each result independently, rather than short-circuiting. It also bears pointing out that both approaches return an uninitialized value whenever all calls succeed.
Jeremy W. Sherman
+1  A: 

If you can define any precise convention about return values you can simply use bitwise or:

int foo() {
  if (function1() | function2() | function3())
    return -1;
  else
    return 0;
}
Jack
That is true but might be too confusing.
Dakota Hawkins
It will call all of them, it's not logical OR but bitwise OR.. there's not lazy evaluation in there..
Jack
@aaaa bbbb: sure it will - thats bitwise or not logical or `||` to complete the bitwise math each method must be called
Greg Domjan
Why not simply `return function1() | function2() | function3();`? I see no need for the conditional statement.
FredOverflow
because in that case you will have `1` for the failure and `0` for the success..
Jack
While in this specific case it works, you should better do `if( (function1() == -1) | (function2() == -1) | (function3() == -1) )`. You have to make explicitely a boolean value (0 or 1) or else you could get strange results. It's a matter of consistency, when using bit-ops for logical operations one should put something in the code to make it clear that it's a logical operation that is performed.
tristopia
-1. This is not equivalent to the original code in that the order in which the three functions are called is not specified. (While the OP didn't say whether this was important, clearly the conservative assumption is that it is.)
John Marshall
@John Marshall: Fix your programming skills - http://en.wikipedia.org/wiki/David_Parnas - check out the first quote
Faheem
@John Marshall: -1 for this useless issue? Just giving predence with parenthesis will allow you to choose whichever order you want. :) You should be less irrevocabile with your intents.
Jack
@Faheemitian: So you're saying that when a newbie asks us for stylistic pointers, Parnas tells us to assume that said newbie's `function[123]` modules are perfectly decoupled from each other and any order of evaluation will be equivalent? And we shouldn't point out the problem just in case said newbie is not a perfect Parnasian? Even when we have no idea what the three modules are? Thanks, that's hilarious...
John Marshall
@Jack: Thanks, your comment demonstrates my point rather nicely! It's a question of order of evaluation, not of precedence -- see http://c-faq.com/expr/precvsooe.html
John Marshall
@John Marshall: What hilarious is that you assume that they are dependent and encourage newbie's for bad programming habits. It is nicer to point out the evaluation order rather than showing off.
Faheem
How arrogant, could swapping function calls be useful to you? Or neither that? You are pointing out something that wasn't considered by anyone just to bark against something. Maybe you had a frustrating day? Try something as punchball to relax yourself..
Jack
John Marshall is exactly right here - I don't know about you guys, but the order that functions are called is almost always vitally important in code that I come across. I'd venture to guess that more than 90% of my coding is putting function calls in the right order.
Michael Burr
+1  A: 

I like the second approach better. If you want one-liners, you can do something like...

char success = 1;

success &= (foo() == desired_result_1);
success &= (bar() == desired_result_2);

etc.

Santiago Lezica
+1  A: 

The 2nd is a "better" approach. However, I'd go more without the needless carrying around of an indicator variable:

if( function2() == -1 ){
    return -1;
}

Suggestion: (no magic numbers)

I'd also not use "magic numbers" like you've used it. Instead:

if( check_fail( function2() ) ){
    return FAILED;
}

more clearly illustrated what you're thinking. Intent is easier to maintain. Magic numbers can sometimes wind up hurting you. For instance, I've known financial guys who couldn't understand why a transaction costing "$-1.00" caused their application to behave abnormally.

wheaties
Given that he states "`Even if one of the function fails i need to go ahead and call the rest of the functions`" your suggested approach doesn't work.
torak
@torak I read that as a limitation to what he said his solution was doing rather than a requirement.
wheaties
A: 

You use bitwise operators to make a 'neat' variant that doesn't need temp variables and has other fancyness too(with the more advanced operators): return func1()|func2();(this is the same as using logical or, ||). However, if you require checking a specific function in the callee, you can create a bitset: return func1() << 1 | func2(); (this assumes that they return 1 or zero)

Necrolis
Another answer that doesn't make the function calls in the same order.
Ben Voigt
@Ben Voigt: never noticed that, however, looking above at John's comments, no remedy is suggested, other than parenthasis, which seems nullified by John's other answer... is there any remedy for this(free of mud slinging)?
Necrolis
@Necrolis: not sure there was much mud, other than that being slung in my direction... anyway: the remedy is given in the C FAQ entry that I pointed Jack towards. If you want a defined order of evaluation, you have to introduce sequence points yourself. Or, in English: you have to write it out the boring and obvious way, with multiple statements and temporary variables.
John Marshall
A: 

I'd vote for the second one as well.

This question reminded me of something similar I do in one of my projects for form validation.

I pass in a reference to an empty string. With each condition I want to check, I either add a line of text to the string, or I don't. If after every test the string is still empty, then there were no errors, and I continue processing the form. Otherwise, I print the string as a message box (which describes the problems), and ask the user to fix the errors.

In this case I don't really care what the errors are, just that there are errors. Oh, and as a bonus, my validation code documents itself a bit because the errors that the user sees are right there.

John at CashCommons
A: 

Use local variable if you need to reuse the result somewhere. Else, call and compare.

Daniel Mošmondor
A: 

I've seen code like this before which might be a little cleaner:

bool result = true;
result = function1() == -1 && result;
result = function2() == -1 && result;
result = function3() == -1 && result;
return result?-1:0;

Edit: forgot about short circuiting.

Niki Yoshiuchi
Stops calling the functions as soon as result is false due to short circuit eval.
Eric Towers
A: 
int foo() {
    return function1() | function2() | function3();
}
nategoose
These answers with unspecified order of execution just keep coming.
Ben Voigt
You're right. I made a bad answer. I didn't think about the differences in order of execution between `|` and `||`
nategoose
A: 

Yet another option: pass a pointer to the status variable to each function and have the function set it only if there is an error.

void function1(int *res)
{
    bool error_flag = false;
    // do work
    if (error_flag && (res != NULL)
    {
       *res = ERROR;
    }
}

// similar for function2, function3, ...

int foo()
{
    int res = OK;
    function1(&res);
    function2(&res);
    function3(&res);
    return res;
}
jholl
A: 

Since all 3 functions always have to get called first and only then you care about the result, I would go for the first solution, because the order of the statements reflects this. Seems more clear to me. Also, I generally don't like functions that do more than just return a value (i.e. that have side effects) in if-clauses, but that's a personal preference.

Sebastian N.
A: 

This sounds like a job for the abundant Perl idiom "<try something> || die()".
int foo() {
     int retVal = 0;
          function1() != -1 || retval = -1;
          function2() != -1 || retval = -1;
          function3() != -1 || retval = -1;
          // ...
     return retVal;
}

Eric Towers
The logic is backwards (you are setting retval to -1 iff the functions don't return -1).
Ben Voigt
@Ben Voigt: Good catch. Edited and fixed.
Eric Towers
+3  A: 

First priority, make the code correct. That's more important than readability and optimization.

That means you need to consider what the function should return in the case where the functions it calls all succeed.

Many of the answers given to this question change the result returned or might return a failure indication if the 'sub-functions' all succeed. you need to take care not to do this.

Personally, I think the overall form of your first option is pretty good - it makes clear that the 3 sub-functions are called regardless of whether one or more of them fail. The one problem is that it returns an indeterminate result if all those functions succeed.

Be wary of answers that use bitwise-or to combine results - there are at least 2 potential problems:

  1. as John Marshall pointed out in several comments, the order of evaluation is indeterminate. This means that if you simply string the function calls with bitwise-or the functions may be called in any order. This might not be a problem if there are no ordering dependencies between the functions, but usually there are - especially if you don't care about the returned value except as a s success/fail indicator (if you aren't using the return value, then the only reason to call the function is for its side effects)

  2. If the functions can return positive, non-zero values when they succeed, then testing for failure becomes a bit trickier than just checking if the results or'ed together are non-zero.

Given these two potential problems, I think there's little reason to try to do anything much fancier than option 1 (or your second option) - just make sure you set res to a success value (0?) for the situation where none of the sub-functions fail.

Michael Burr
A: 

I write it this way:

int foo()
{
    int iReturn = 0;

    int res1 = function1();
    if (res1 == -1)
    {
        return  iReturn; 
    }

    int res2 = function2();
    if (res2 == -1)
    {
        return  iReturn; 
    }

    int res3 = function3();
    if (res3 == -1)
    {
        return  iReturn; 
    }

    return res;
}

As a coding rule, you should declare your variables as close to the place where it is used.

It is good to use intermediate variable like your res1, res2, res3. But choose a good name so as you intent is clear when you get the value from the function.

And be careful, in the example you've given us, you never assigned the int res; that may be returned when success. The coding rule is to initialize your variable as soon as you can. So you should also initialize your res1 res2 res3 immidiatbly.

Returning an uninitialized value leads to undefined behaviour.

Stephane Rolland
+1  A: 

In the first form you're not checking the status until all 3 calls are completed. I think this signals your intent the clearest. The second form more closely resembles the more usual case, where you return early if an error is detected.

It's a subtle thing either way. You shouldn't be asking us strangers on the internet, you should be asking the rest of your team, because they're the ones who will have to live with it.

Mark Ransom