Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bad Use of Null Coalescing Operator?

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?

like image 949
Chris Avatar asked Nov 24 '09 18:11

Chris


People also ask

Why should Unity objects not use null propagation?

Object is destroyed, even if the object itself isn't actually null. Null propagation cannot be overridden in this way, and therefore behaves inconsistently with the == operator, because it checks for null in a different way.

Why we use null coalescing operator?

The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null ; otherwise, it evaluates the right-hand operand and returns its result. The ?? operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null.

Can I use Nullish coalescing operator?

You can use the nullish coalescing assignment operator to apply default values to object properties. Compared to using destructuring and default values, ??= also applies the default value if the property has value null .

Which is null coalescing operator?

The nullish coalescing operator ( ?? ) is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined , and otherwise returns its left-hand side operand.


1 Answers

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!

like image 106
AakashM Avatar answered Oct 17 '22 04:10

AakashM