views:

219

answers:

3
myFoo = myFoo ?? new Foo();

instead of

if (myFoo == null) myFoo = new Foo();

Am I correct in thinking that the first line of code will always perform an assignment? Also, is this a bad use of the null-coalescing operator?

+3  A: 

You are correct in that the first line will always make an assignment. I would not worry about that unless the code is executed very often.

Fredrik Mörk
What should stop the compiler from optimizing it away?
Timbo
@Timbo: I am not too knowledgeable about which optimizations the compiler may or may not do, but I make the assumption that `myFoo` will be used elsewhere in the code and that this would prevent the compiler from optimizing it away. If it is not used elsewhere, it's a different story.
Fredrik Mörk
+5  A: 

I don't think this a bad use of the null-coalescing operator. When reading the code, it is as short and concise as possible, and the intent of the code is obvious.

It is correct that using the null-coalescing operator like this, you will always get an assignment, but I would not worry about that. (And if it really turns out to be a performance issue, you already know how to fix it).

driis
+12  A: 

I compared the CIL of the generated code (making sure to do a Release build - with Optimize Code checked in the Project Properties, which corresponds to the /optimize switch on csc.exe). This is what I got (using VS 2008 - note that Foo.MaybeFoo() is a method that sometimes returns null, sometimes a Foo)

GetFooWithIf:

  IL_0000:  call       class Application3.Foo Application3.Foo::MaybeFoo()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  brtrue.s   IL_000f
  IL_0009:  newobj     instance void Application3.Foo::.ctor()
  IL_000e:  stloc.0
  IL_000f:  ldloc.0
  IL_0010:  ret

GetFooWithCoalescingOperator:

  IL_0000:  call       class Application3.Foo Application3.Foo::MaybeFoo()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  dup
  IL_0008:  brtrue.s   IL_0010
  IL_000a:  pop
  IL_000b:  newobj     instance void Application3.Foo::.ctor()
  IL_0010:  stloc.0
  IL_0011:  ldloc.0
  IL_0012:  ret

Thus, the same except for an extra top-of-stack-duplication and pop. If this can be made to make a measurable performance difference, I will purchase a hat specifically for the purpose of eating it; therefore, go with the one that you feel offers better readability.

(edit) oh, and the JITter might be clever enough to get rid of even that difference!

AakashM
Is this with `csc.exe /optimize+`?
Pavel Minaev
I think so, edited to clarify.
AakashM