To use “else” or separate “if”s when each has a return?

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
Qaanol
The Cheshirest Catamount
Posts: 3069
Joined: Sat May 09, 2009 11:55 pm UTC

To use “else” or separate “if”s when each has a return?

Postby Qaanol » Thu Dec 26, 2013 7:09 pm UTC

I have a function (actually, an Objective-C method) which has essentially the following format:

Code: Select all

if (a) {
  // Calculate stuff
  return x;
} else {
  // Calculate stuff
  if (b) {
    // Calculate stuff
    return y;
  } else {
    // Calculate stuff
    return z;
  }
}


This could also be written:

Code: Select all

if (a) {
  // Calculate stuff
  return x;
}

// Calculate stuff
if (b) {
  // Calculate stuff
  return y;
}

// Calculate stuff
return z;


Is there any benefit of doing one or the other?

Aesthetically, I prefer the second version because it reduces the level of nested indentations. Also, it makes it visually clear that the function definitely returns something, whereas someone reading the first version would have to look at each “if” block and verify that it will always hit a “return”. On the other hand, the first version makes it obvious that the code is structured as mutually-exclusive blocks.

So I’m wondering if there is a general consensus as to whether one style is preferred, either for code-reading or for compiler-optimization reasons.
wee free kings

arbyd
Posts: 24
Joined: Thu Feb 11, 2010 4:33 pm UTC

Re: To use “else” or separate “if”s when each has a return?

Postby arbyd » Thu Dec 26, 2013 9:22 pm UTC

I like to set a variable to the return value. This gives you a single exit point for the function. If applicable, you can use this style with a switch statement. If the function has a defined error return, I initialize the variable to the error value.

Code: Select all

int returnCode = ERRCODE;
if (a) {
    // Calculate stuff
    returnCode = x;
} else {
    if (b) {
        // Calculate stuff
        returnCode = y;
    }
    else {
        // Calculate stuff
        returnCode = z;
}
return returnCode;

User avatar
Xeio
Friends, Faidites, Countrymen
Posts: 5101
Joined: Wed Jul 25, 2007 11:12 am UTC
Location: C:\Users\Xeio\
Contact:

Re: To use “else” or separate “if”s when each has a return?

Postby Xeio » Fri Dec 27, 2013 1:25 am UTC

arbyd wrote:I like to set a variable to the return value.
Look, well, I hate you.

Bonus annoyance with that sample, the ERRCODE value is misleading since it's never used. But you don't know that unless you read the whole function.

User avatar
Steax
SecondTalon's Goon Squad
Posts: 3038
Joined: Sat Jan 12, 2008 12:18 pm UTC

Re: To use “else” or separate “if”s when each has a return?

Postby Steax » Fri Dec 27, 2013 3:10 am UTC

I typically go with separate ifs, but only if the code blocks are short enough (3-4 lines tops) to be sure that each return is in place (since missing a return would probably end in catastrophic results). If it's longer, I'd either break it up into smaller method calls or use elses.
In Minecraft, I use the username Rirez.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: To use “else” or separate “if”s when each has a return?

Postby EvanED » Fri Dec 27, 2013 4:34 am UTC

I'd prefer the separate returns, unless the body of the outer if can reasonably and logically be broken out into a separate function (e.g. a version of the outer function that has stricter preconditions), in which case doing that would be reasonable too.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11120
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: To use “else” or separate “if”s when each has a return?

Postby Yakk » Fri Dec 27, 2013 8:21 pm UTC

Does your language have RAII? Full born garbage collection? If so, early exit is sweet. Just make sure all resources are RAII owned.

If not, early exit makes any resource management in your code a serious mess.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
poxic
Eloquently Prismatic
Posts: 4751
Joined: Sat Jun 07, 2008 3:28 am UTC
Location: Left coast of Canada

Re: To use “else” or separate “if”s when each has a return?

Postby poxic » Fri Dec 27, 2013 8:25 pm UTC

Xeio wrote:
arbyd wrote:I like to set a variable to the return value.
Look, well, I hate you.

Huh. Most of the code where I work seems to use the variable-with-return-value option. Or case statements, which are almost the same thing.
In everyone's life, at some time, our inner fire goes out. It is then burst into flame by an encounter with another human being. We should all be thankful for those people who rekindle the inner spirit.
- Albert Schweitzer, philosopher, physician, musician, Nobel laureate (14 Jan 1875-1965)

lgw
Posts: 437
Joined: Mon Apr 12, 2010 10:52 pm UTC

Re: To use “else” or separate “if”s when each has a return?

Postby lgw » Fri Dec 27, 2013 8:42 pm UTC

I prefer the second example in general: it seems to age better, it's cleaner to comment, and I in general try to keep code in the body of any conditional block as simple as I can. (As an aside, I loathe code that's afraid to return from the middle of a function, and obfuscates to avoid that.)

If seems to be a common pattern to do:

Code: Select all

// Handle bad things.
if (InputIsBad(a))
{
   return/throw "bad input";
}

// Handle good things.
if (ThatEasySpecialCase(a, b)))
{
   return 0;
}

// Do the thing.
int result = CalculateStuff(a);
result += SomeOtherStuff(b);
return result;


Only in the rare case that the business logic of the function actually has two non-trivial branches will I use an if/else pattern, and then I'll often refactor the branches into separate functions.

Code: Select all

if (a > SometimesItsDifferent(b))
{
   return SomeComplexLogic(a, b);
}
else
{
   return DifferentComplexLogic(a, b);
}


Another case where I used to use an if/else pattern is when I'm just selecting one of several simple results, or just dispatching the right function out of many, and for whatever reason I can't use a switch/case. In that special case I'll often omit the brackets or even use single line ifs to emphasize the dispatcher-nature of the code (depending on local coding standards):

Code: Select all

if      (MatchesRegex1(a))  return DoThing1(a);
else if (MatchesRegex2(a))  return DoThing2(a);
else if (MatchesRegex3(a))  return DoThing3(a);
else                        return DoThing4(a);


But these days I'm working in languages where it's more clear to refactor out those ifs entirely, as in C#'s:

Code: Select all

return handlers.First(handler => handler.Matches(a)).DoThing(a);
"In no set of physics laws do you get two cats." - doogly

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6569
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: To use “else” or separate “if”s when each has a return?

Postby Thesh » Fri Dec 27, 2013 9:31 pm UTC

poxic wrote:
Xeio wrote:
arbyd wrote:I like to set a variable to the return value.
Look, well, I hate you.

Huh. Most of the code where I work seems to use the variable-with-return-value option. Or case statements, which are almost the same thing.


Is it C code in this format?

Code: Select all

//acquire resources
if (something) {
    //do something
}
else if (something) {
  //do something else
}
else {
  //do other stuff
}
//release resources
return value;


Because I can understand that. I can't really understand why you would do it otherwise, at best you accomplish nothing, at worst you forget to set the return value at one branch, the compiler won't warn you, and you introduce a difficult to track down bug.

If I have a function that does one main thing, but has special cases, I will not have an else. If it's not a special case but entirely different code depending on the parameters, I will first consider refactoring into multiple functions, but otherwise I will do if/else, just because the compiler will warn me (or in C#, fail to compile) if I forget to return, which is nice for preventing future bugs.
Summum ius, summa iniuria.

User avatar
poxic
Eloquently Prismatic
Posts: 4751
Joined: Sat Jun 07, 2008 3:28 am UTC
Location: Left coast of Canada

Re: To use “else” or separate “if”s when each has a return?

Postby poxic » Fri Dec 27, 2013 9:46 pm UTC

It's SQL, actually. I no programmer enough to talk intelligently about it, but typical code looks like this.

Code: Select all

if (thingy)
then
    -- do stuff
    retcode = A
else if (thingy)
then
    -- do other stuff
    retcode = B
else retcode = buggrit
return retcode
In everyone's life, at some time, our inner fire goes out. It is then burst into flame by an encounter with another human being. We should all be thankful for those people who rekindle the inner spirit.
- Albert Schweitzer, philosopher, physician, musician, Nobel laureate (14 Jan 1875-1965)

User avatar
Qaanol
The Cheshirest Catamount
Posts: 3069
Joined: Sat May 09, 2009 11:55 pm UTC

Re: To use “else” or separate “if”s when each has a return?

Postby Qaanol » Sat Dec 28, 2013 3:47 am UTC

arbyd wrote:I like to set a variable to the return value. This gives you a single exit point for the function. If applicable, you can use this style with a switch statement. If the function has a defined error return, I initialize the variable to the error value.

Code: Select all

int returnCode = ERRCODE;
if (a) {
    // Calculate stuff
    returnCode = x;
} else {
    if (b) {
        // Calculate stuff
        returnCode = y;
    }
    else {
        // Calculate stuff
        returnCode = z;
}
return returnCode;


lgw wrote:If seems to be a common pattern to do:

Code: Select all

// Handle bad things.
if (InputIsBad(a))
{
   return/throw "bad input";
}

// Handle good things.
if (ThatEasySpecialCase(a, b)))
{
   return 0;
}

// Do the thing.
int result = CalculateStuff(a);
result += SomeOtherStuff(b);
return result;


Thanks everyone, I’m glad to get varied perspectives on this.

It turns out my code which prompted this thread actually kind of uses both of the above patterns within a single method (so I’ll probably catch flak from both sides now.) I’ve got the “handle easy cases” up top, then an attempt to derive an easy case from messy input, and if that fails then I have a section at the bottom to create a new result from scratch, and in that part I create an output variable, initialize it to a default value, then go through some cases to determine whether to change it.

What I’m doing is making a “nice” subclass of NSNumberFormatter, because the default implementation will not let you exit a text field until you have entered a valid numeric string, even though it lets you enter arbitrary text (and it doesn’t give any feedback or hints, it just refuses to give up focus as long as anything non-numeric is there.) My subclass still lets you enter arbitrary text, but when you go to leave the field it queries the default implementation to find out if the string is valid, and if not it truncates until it reaches a valid string. If it has to truncate all the way to an empty string, then it creates a new value which is as close to zero as possible while respecting the minimum and maximum specified in the number formatter.

Code: Select all

- (BOOL)getObjectValue:(out __autoreleasing id *)obj
             forString:(NSString *)string
                 range:(inout NSRange *)rangep
                 error:(out NSError *__autoreleasing *)error
{
    if ([string length] && (!rangep || rangep->length) &&
        [super getObjectValue:obj forString:string range:rangep error:error])
    {
        // The input string is valid and non-empty, so run with it
        return YES;
    }
   
    // We have to truncate
    if (!rangep) {
        // Do not start with [string length]-1 because that might be -1
        NSRange r = NSMakeRange(0, [string length]);
        rangep = &r;
    }
   
    while (rangep->length && ![super getObjectValue:obj
                                          forString:string
                                              range:rangep
                                              error:nil]) {
        rangep->length--;   // Truncate, truncate, truncate...
    }
   
    if (rangep->length) {
        // We found a valid maximal non-empty initial substring
        return [super getObjectValue:obj
                           forString:string
                               range:rangep
                               error:error];
    }
   
    // The first character was invalid
    NSNumber *zeroNumber = [NSNumber numberWithInt:0];
    NSNumber *minVal = [self minimum];
    NSNumber *maxVal = [self maximum];
    NSNumber *newNumber = zeroNumber;
   
    if (minVal && [minVal compare:zeroNumber] == NSOrderedDescending) {
        newNumber = minVal;
    } else if (maxVal && [maxVal compare:zeroNumber] == NSOrderedAscending) {
        newNumber = maxVal;
    }
   
    string = [self stringFromNumber:newNumber];
    rangep->location = 0;
    rangep->length = [string length];
   
    return [super getObjectValue:obj
                       forString:string
                           range:rangep
                           error:error];
}
wee free kings

korona
Posts: 495
Joined: Sun Jul 04, 2010 8:40 pm UTC

Re: To use “else” or separate “if”s when each has a return?

Postby korona » Sat Dec 28, 2013 1:21 pm UTC

IMHO return values in variables should only be used if there is a reason to do that e.g. if the method releases resources after it's done and you don't want to copy the release code into each branch.

I prefer simple ifs over if - else constructs because it keeps the indentation level small and IMHO it's easier to read.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: To use “else” or separate “if”s when each has a return?

Postby Jplus » Thu Jan 09, 2014 9:47 am UTC

Sorry for necromancing this thread. It seems my particular take hasn't been mentioned yet.

Code: Select all

type retval;

if (a) {
  // Calculate stuff
  retval = x;
}

// Calculate stuff
else if (b) {
  // Calculate stuff
  retval = y;
}

else {
  // Calculate stuff
  retval = z;
}

return retval;


In general I'm totally fine with return-in-the-middle, but using a variable for the return value sometimes helps the compiler to enable RVO.

Unless it's easy to see that the options are really mutually exclusive, you should emphasize that using else.

It is acceptable to flatten if - else if - else chains.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
Yakk
Poster with most posts but no title.
Posts: 11120
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: To use “else” or separate “if”s when each has a return?

Postby Yakk » Thu Jan 09, 2014 11:23 am UTC

Why not return retval in the middle then?
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: To use “else” or separate “if”s when each has a return?

Postby EvanED » Thu Jan 09, 2014 5:28 pm UTC

Jplus wrote:Sorry for necromancing this thread. It seems my particular take hasn't been mentioned yet.

That's because if you actually fill out the marked "calculate stuff" with real code you'll get a compiler error because you have an else if with no if:

Code: Select all

type retval;

if (a) {
  // Calculate stuff
  retval = x;
}

// Calculate stuff   <---- ****
else if (b) {
  // Calculate stuff
  retval = y;
}

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: To use “else” or separate “if”s when each has a return?

Postby Jplus » Fri Jan 10, 2014 12:55 pm UTC

Hm, good point. Comments are easy to overlook.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
skeptical scientist
closed-minded spiritualist
Posts: 6142
Joined: Tue Nov 28, 2006 6:09 am UTC
Location: San Francisco

Re: To use “else” or separate “if”s when each has a return?

Postby skeptical scientist » Fri Feb 28, 2014 3:44 am UTC

Xeio wrote:
arbyd wrote:I like to set a variable to the return value.
Look, well, I hate you.

Bonus annoyance with that sample, the ERRCODE value is misleading since it's never used. But you don't know that unless you read the whole function.

The advantage of initializing to ERRCODE is if you somehow reach the final "return returnCode;" line without setting returnCode, you return ERRCODE (which signifies the error) instead of returning a default 0-initialized int (which generally counts as success).

Here's one reason why that might be preferable (although in this particular case initializing to an error value would not have helped, because each "if" statement assigns to the return value variable). :P
I'm looking forward to the day when the SNES emulator on my computer works by emulating the elementary particles in an actual, physical box with Nintendo stamped on the side.

"With math, all things are possible." —Rebecca Watson

Rysto
Posts: 1460
Joined: Wed Mar 21, 2007 4:07 am UTC

Re: To use “else” or separate “if”s when each has a return?

Postby Rysto » Sun Mar 16, 2014 8:59 pm UTC

skeptical scientist wrote:The advantage of initializing to ERRCODE is if you somehow reach the final "return returnCode;" line without setting returnCode, you return ERRCODE (which signifies the error) instead of returning a default 0-initialized int (which generally counts as success).

No, what you do is not initialize it to anything, and any modern compiler will warn you if you have code paths that don't initialize it. Initializing the variable unnecessarily just leaves a landmine when people go to modify the code in the future.

(of course, if you have a unit test suite the risk is lower, but there's a lot of code out there without unit tests)


Return to “Coding”

Who is online

Users browsing this forum: Baidu [Spider] and 10 guests