tags:

views:

250

answers:

8

Is there a performance difference between the following two pieces of code?

if (myCondition)
{
     return "returnVal1";
}

return "returnVal2"

and

if (myCondition)
{
     return "returnVal1";
}
else
{
     return "returnVal2";
}

My gut feeling is that the compiler should optimize for this and there shouldn't be a difference, but I frequently see it done both ways throughout our code. I'd like to know if it comes down to a matter of preference and readability.

+13  A: 

I'm pretty certain the compiler will optimize that out. Do what is most readable/follows convention for you and let the compiler handle simple things like that.

Even if it was not optimized, the performance difference would be pretty negligible.

CookieOfFortune
As you said, performance impact here is nil to negligible, so it comes down to a matter of emphasis. If you want the two possibilities to be understood as equal, it may be clearer to use if/then/else. If one possibility is a special case, such as not being able to continue due to missing data, then it may be clearer to use if/then to avoid hitting what used to be in the else.
Steven Sudit
A: 

With regards to the question, no it will not have a performance issue unless the case you are always evaluating turns out to be the else clause.

As stated in comments, you should just return the myCondition. However, you should always include an else clause for readability. If the else does nothing, then state so, with the classic comment of:

//do nothing

It helps developers looking at the code after it's written to realize that the else case was considered, but that there is no situation where it exists. It's also a good place to document why there ISN'T an else.

The example where a performance hit would occur is the following:

int x = 2;

if x != 2 {
     return true;
} else {
     return false;
}

The case being that it will always checks the if clause, fails, and therefore has to check the else clause.

Edit: If the else clause does nothing, the compiler will skip it -- it just comes in handy for reading purposes of other developers. it can also make your code more concise:

if(x=2) {
      doThis();
}
if(x!=2){
      doThat();
}

can get confusing and is easily combined into:

if(x==2){
     doThis(); 
} else {
     doThat();
}
MunkiPhD
I'm pretty certain that the condition will be evaluated only once.
Burkhard
There is nothing to check for the else clause. Most likely the compiler will make a single jump and a fall through for the entire if/else.
Brian Rasmussen
In any normal compiler's output, there is only one check. It wouldn't perform two checks. What you have there is wrong because the code in one branch is just worthless. But, it wasn't performing worse that it would have.
John Fisher
I think a difference would occur if you put a return true at the very end. (Although, a good compiler might optimize that out as well? Maybe if you were using non-boolean types).
CookieOfFortune
For this simple example I'd **return (x != 2)**, however if myCondition become any more complex I'd split it into an if statement to improve readability.
ParmesanCodice
The condition will be evaluated only once and then a jump will happen or not. After the branch ran, the code returns. No compiler can change this pattern much. Maybe a conditional load, but that's it.
Daniel Brückner
I agree, it's for example's sake. I was assuming that the condition might be something like isCustomerMale, when 99% of your customers are actually female. You have to know what you're working with, but you really want to aim towards readability first, optimization after.
MunkiPhD
+4  A: 

If your compiler does not optimize it to the same bytecode, throw it out of the window!

Burkhard
+5  A: 

While the optimization is a good thing, readability plays an important thing as well, so if you think if helps readability it's better than the nanosecond you save. IMHO

MexicanHacker
+11  A: 

The best way to find out is to look at the code! Here's the code the VS2005 C# produced in release mode:

 static bool F1 (int condition)
 {
   if (condition > 100)
00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  push        eax  
00000004  mov         dword ptr [ebp-4],ecx 
00000007  cmp         dword ptr ds:[009185C8h],0 
0000000e  je          00000015 
00000010  call        79469149 
00000015  cmp         dword ptr [ebp-4],64h 
00000019  jle         00000024 
   {
  return true;
0000001b  mov         eax,1 
00000020  mov         esp,ebp 
00000022  pop         ebp  
00000023  ret              
   }

   return false;
00000024  xor         eax,eax 
00000026  mov         esp,ebp 
00000028  pop         ebp  
00000029  ret              
            }

 static bool F2 (int condition)
 {
   if (condition > 100)
00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  push        eax  
00000004  mov         dword ptr [ebp-4],ecx 
00000007  cmp         dword ptr ds:[009185C8h],0 
0000000e  je          00000015 
00000010  call        79469109 
00000015  cmp         dword ptr [ebp-4],64h 
00000019  jle         00000024 
   {
  return true;
0000001b  mov         eax,1 
00000020  mov         esp,ebp 
00000022  pop         ebp  
00000023  ret              
   }
   else
   {
  return false;
00000024  xor         eax,eax 
00000026  mov         esp,ebp 
00000028  pop         ebp  
00000029  ret              
            }

Which shows the two version produce the exact same code, as you would hope for. I also tried a third option:

 static bool F3 (int condition)
 {
   return condition > 100;
00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  push        eax  
00000004  mov         dword ptr [ebp-4],ecx 
00000007  cmp         dword ptr ds:[009185C8h],0 
0000000e  je          00000015 
00000010  call        794690C9 
00000015  cmp         dword ptr [ebp-4],64h 
00000019  setg        al   
0000001c  movzx       eax,al 
0000001f  mov         esp,ebp 
00000021  pop         ebp  
00000022  ret              
            }

which is far more efficient as it never branches (and branches are usually bad!).

Skizz

EDIT

Actually, the best way to find out which is more efficient is to profile the code, not look at the assembler.

Also, the code it's produced is quite unusual. The push eax / mov [],ecx bit is the same, surely, as a single push ecx. Also, it passes by register then stores the value on the stack. I wonder if running the code in the debugger to look at the assembler is changing the way the code is generated.

Skizz
isn't je a branch?
CookieOfFortune
Of course, I've used a bool return value. Returning a string, F3 generates the same code as F1 and F2.
Skizz
The je is common to all three versions. I was excluding common housekeeping overhead.
Skizz
How about immediate if?
Steven Sudit
sorry, I was just nitpicking your use of "never branches".
CookieOfFortune
+1  A: 

You could discover this for yourself, by creating a test project with these two variations in it. Then, open the project in ildsam or Reflector to see the disassembly. You'll know exactly what's going on then.

John Fisher
A: 
Sarkazein
It's not a best practice, but it used to be back before exception-safe coding and RIAA.
Steven Sudit
I wouldn't say 'best practice' but it is something I personally like to do. With compilers being as good as they are, I don't think it makes a difference whether you have one return or multiple returns, so it's down to personal preference.
Skizz
Well, he did call it a best practice, which is inaccurate. I think we all agree that doing it one way or the other will have no effect on performance, so it comes down to what makes the code clearer, rather than personal preference. Clarity comes from accurately communicating intent, and in many cases, if/then/else does not match my intent at all.
Steven Sudit
I'm calling it that because when you have multiple return points in a single method, it can make debugging much more difficult. It's not necessarily anything to do with performance. It's more about human readability. If you know there is exactly one return point, it's easier to trace to that rather than to two or more possible return points.
Sarkazein
In general I share your opinion, but when talking about human readability do not let out optional curly braces...
Marc Wittke
for(int i = 0; i < a; i++) { for(int j = 0; j < b; j++) { if (arr[i][j] == ERROR) { return ERROR; } sum += calc(arr[i][j]); }}return sum;vsfor(int i = 0; i < a; i++) { for(int j = 0; j < b; j++) { if (arr[i][j] == ERROR) { result = ERROR; break; } sum += calc(arr[i][j]); } if (result == ERROR) { break; }}if (result != ERROR){ result = sum;}return result;I would say the first version is certainly more readable.
CookieOfFortune
@CookieOfFortune: written on one line, they are both quite hard to read.
Burkhard
@Marc: Mandatory braces in "then" clauses were iffy to begin with and became entirely obsolete once editors routinely reformatted indentation. It's now very difficult to recreate the error of omitting braces when the "then" is composite.
Steven Sudit
@Cookie: Your example was clobbered.
Steven Sudit
@Sarkazein: When I have to choose between readability and debugability, I go with the former unless the latter becomes significant.
Steven Sudit
+2  A: 

I would be very surprised if there were a performance hit and the code suggests that there isn't.

After many years of trying to figure out legacy code in which multiple coders have tried to optimise expressions at the editor and have produced amazingly impenetrable code, I can only say that you should write what makes sense and expresses what you want in the simplest and clearest way.

All of the code snippets are easy to figure out because they are small but imagine the logic spread out over several pages ...

Dr. Tim