tags:

views:

297

answers:

9

Do the following 2 code snippets achieve the same thing?

My original code:

if (safeFileNames != null)
{
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value);
}
else
{
    this.SafeFileNames = false;
}

What ReSharper thought was a better idea:

this.SafeFileNames = safeFileNames != null && 
                     Convert.ToBoolean(safeFileNames.Value);

I think the above code is much easier to read, any compelling reason to change it? Would it execute faster, and most importantly, will the code do the exact same thing?

Also if you look at the : Convert.ToBoolean(safeFileNames.Value); section, then surely this could cause a null reference exception?

this.SafeFileNames = bool... Local safeFileNames is a strongly typed custom object, here is the class:

public class Configuration
    {
        public string Name
        {
            get;
            set;
        }
        public string Value
        {
            get;
            set;
        }
    }
A: 

Yes, they are the same, no it will not be any faster. The syntax is called a ternary operator, and can replace the if/else statement. It is more concise, but if it's easier to ready it a matter of preference.

cadmium
Brian Frantz
This is not a ternary operator; it's making use of the fact that, if the first half of an AND statement is false, the second half is not evaluated. The ternary operator approach would be "this.SafeFileNames = (safeFileNames != null)?Convert.ToBoolean(safeFileNames.Value):false;" which I'd say is even more confusing.
JacobM
-1 This does not use the ternary operator it is just using boolean logic.
ScottS
"... no it will not be any faster" -- see reference to Short-Circuit above; in some cases it will in fact be faster.
Hardryv
+4  A: 

Both statements do the exact same thing. Which to use is a matter of preference, but I prefer Resharper's version. More concise, less moving parts. Easier to see the intent of the code.

Brian Frantz
What if this.SafeFileNames is null? Surely trying to Convert.ToBoolean on a null, would cause a null reference exception?
JL
@JL: the second clause would never execute if SafeFileNames were null
Randolpho
Short circuiting for the win.
J. Steen
+1  A: 

They're the same. The && is a short-circuiting operator so the second half of the expression won't evaluate if safeFileNames is null.

Mark Byers
+1  A: 

They are the same. In the one-liner, if the first condition fails, the second is not evaluated. So you don't get a null reference.

I bet the IL is the same in both cases.

I prefer the second version.

nickd
+23  A: 

The fact that you asked the question suggests to me that the former is preferred. That is, it seems to me that your question implies that you believe the first code to be easier to understand, and you aren't quite sure if the second is equivalent. A primary goal of software design is to manage complexity. If it's confusing to you now, it may also be to you later, or to whomever supports your code down the road.

Dave
This is a great answer.
Jason
+1 to KISS [15]
Jon B
Very good way to look at it.
Aequitarum Custos
I fully agree, but I'm going to change it. I think its something every .net developer should know. So I feel a bit bad for not having known this.. but thanks to everyone for the awesome lesson...
JL
This got lost in my whole null coalesce operator post, and for that I am truly sorry. Great answer!
Randolpho
a great answer indeed, but I'd recommend you go with ReSharper's method since you presumably understand what he's about now, and it looks potentially faster (given the Short-Circuit support)
Hardryv
Yep. Consider that the poor shlub who gets to fix your code at 10:00pm the Friday before deployment could be *you* months from now. Also leave enough clues *(comments)* in the code to reconstruct your thinking about the program logic.
Loadmaster
+2  A: 

It reduces the cyclomatic complexity of your code by using the resharper suggestion.

Whether it's easier to read or not, is a personal opinion, however I prefer the suggestion resharper gave you.

They are identical, and if you want readability, I could also suggest the following:

if (safeFileNames != null)
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value);
else
    this.SafeFileNames = false;

or

this.SafeFileNames = safeFileNames != null ? Convert.ToBoolean(safeFileNames.Value) : false
Aequitarum Custos
Note: Removing braces to me when they are unnecessary makes code look better, again, very opinion based.
Aequitarum Custos
@Aequtarium, your answer is not incorrect or inefficient. It's just not as exciting as the others, I guess. Voting you up.
Robert Harvey
It is an opinion, but worth noting that StyleCop will flag this as an error. Consistency is one factor; the other is introducing an error when you add your second statement in an if (without an else) and forget to add your braces as well. IDE will usually indent it and notify you, but if you happen to be using Visual Notepad....
Dave
A: 

Yep both those statements will do the same thing, you don't have to take re-sharpers suggestions as gospel, what one man considers to be readable code is another mans mess.

There are a few other ways to do what your trying to do that might be more readable, what value type is safeFileNames? It looks like it may be a nullable bool? If so you could simply just write,

this.SafeFileNames = safeFileNames.GetValueOrDefault();
mattdlong
A: 

Logically, they're identical. Any performance difference would likely be neglible. It's possible that the second form would translate to more efficient binary code on some platforms since the second form does away with a conditional. Conditionals (incorrect speculative execution) can mess up your CPU's instruction pipeline in CPU-intensive work. However, both the IL and the JITter need to emit code of adequate quality for this to make much difference.

I agree with your sense of readability, but I don't assume everyone shares that.

George Spofford
+5  A: 

Here's IL for both pieces of code. I took your code and created a console app to take a look at the IL. As you can see from the resulting IL, one method (method2) is 4 bytes shorter, but the IL that runs for both is pretty much the same, so as far as performance goes... don't worry about that. They both will have the same performance. Focus more on which one is easier to read and better demonstrates your intent.

My code:

class Program
{
    static void Main(string[] args)
    {


    }
    public void method1()
    {
        bool? safeFileNames = null;

        if (safeFileNames != null)
        {
            SafeFileNames = Convert.ToBoolean(safeFileNames.Value);
        }
        else
        {
            SafeFileNames = false;
        }
    }
    public void method2()
    {
        bool? safeFileNames = null;
        SafeFileNames = safeFileNames != null && Convert.ToBoolean(safeFileNames.Value);
    }
    public static bool SafeFileNames { get; set; }
}

The IL for method 1:

.method public hidebysig instance void  method1() cil managed
{
  // Code size       42 (0x2a)
  .maxstack  1
  .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames)
  IL_0000:  ldloca.s   safeFileNames
  IL_0002:  initobj    valuetype [mscorlib]System.Nullable`1<bool>
  IL_0008:  ldloca.s   safeFileNames
  IL_000a:  call       instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue()
  IL_000f:  brfalse.s  IL_0023
  IL_0011:  ldloca.s   safeFileNames
  IL_0013:  call       instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value()
  IL_0018:  call       bool [mscorlib]System.Convert::ToBoolean(bool)
  IL_001d:  call       void ConsoleApplication5.Program::set_SafeFileNames(bool)
  IL_0022:  ret
  IL_0023:  ldc.i4.0
  IL_0024:  call       void ConsoleApplication5.Program::set_SafeFileNames(bool)
  IL_0029:  ret
} // end of method Program::method1

The IL for method2:

.method public hidebysig instance void  method2() cil managed
{
  // Code size       38 (0x26)
  .maxstack  1
  .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames)
  IL_0000:  ldloca.s   safeFileNames
  IL_0002:  initobj    valuetype [mscorlib]System.Nullable`1<bool>
  IL_0008:  ldloca.s   safeFileNames
  IL_000a:  call       instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue()
  IL_000f:  brfalse.s  IL_001f
  IL_0011:  ldloca.s   safeFileNames
  IL_0013:  call       instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value()
  IL_0018:  call       bool [mscorlib]System.Convert::ToBoolean(bool)
  IL_001d:  br.s       IL_0020
  IL_001f:  ldc.i4.0
  IL_0020:  call       void ConsoleApplication5.Program::set_SafeFileNames(bool)
  IL_0025:  ret
} // end of method Program::method2
TskTsk
If I could give this more than 1 point I would, I love when people check the IL to determine actual differences.
Aequitarum Custos
+1 for the extreme effort, and many thanks!
JL
Seemed like a good excuse to dust off ildasm and play around for a while :-)
TskTsk
+1 I was too lazy... :)
Dave