开发者

Does the compiler optimize the Null Coalescing operator when used for self assignment?

开发者 https://www.devze.com 2023-03-14 23:41 出处:网络
These two code blocks are functionally the same if (myObj == null) { myObj 开发者_如何学JAVA= new MyObj();

These two code blocks are functionally the same

if (myObj == null)
{
    myObj 开发者_如何学JAVA= new MyObj();
}

and

myObj = myObj ?? new MyObj();

However, the one using the null coalescing operator does an unnecessary assignment in the case where myObj is not null. But then I thought maybe the compiler optimizes these self assignments. Does anyone know if the compiler will notice what is going on and essentially convert the bottom snippet into the top one?


For comparison purposes, I tried compiling both

object myObj = null;
myObj = myObj ?? new object();

and

object myObj = null;
if(myObject == null)
{
  myObj = new object();
}

inside of the Main method. (I am using MonoDevelop 2.4 on Mono 2.6.7)

If the code were optimized as expected, we should see similar IL being generated. Here is the IL for the first version of Main:

.method public static  hidebysig 
       default void Main (string[] args)  cil managed 
{
    .entrypoint
    .maxstack 3
    .locals init (
            object  V_0)
    IL_0000:  ldnull 
    IL_0001:  stloc.0 
    IL_0002:  ldloc.0 
    IL_0003:  dup 
    IL_0004:  brtrue IL_000f

    IL_0009:  pop 
    IL_000a:  newobj instance void object::'.ctor'()
    IL_000f:  stloc.0 
    IL_0010:  ret 
}

and for the second version:

.method public static  hidebysig 
       default void Main (string[] args)  cil managed 
{
    .entrypoint
    .maxstack 1
    .locals init (
            object  V_0)
    IL_0000:  ldnull 
    IL_0001:  stloc.0 
    IL_0002:  ldloc.0 
    IL_0003:  brtrue IL_000e

    IL_0008:  newobj instance void object::'.ctor'()
    IL_000d:  stloc.0 
    IL_000e:  ret 
}

So the first version (using the null-coalescing operator) has generated slightly more IL.

But there are two things to note about this:

  1. This IL is what I got using MoveDevelop - if you compile it in Visual Studio, it could very well have been a different story. Perhaps it is optimized in Microsoft's with compiler. And even if it's the same with them, another person's compiler could easily optimize this. Just because something holds for some compilers, doesn't mean you would expect it from everybody's compiler.
  2. The CLR makes use of a JIT. Even if this wasn't optimized at compile-time, it probably would have been optimized at run-time. In fact, this may very well be why the compile isn't so concerned about such a micro-optimization.


Just tried it in LinqPad:

void Main()
{
    MyObj myObj = null;
    myObj = myObj ?? new MyObj();
}

This gives the following IL:

IL_0000:  ldnull      
IL_0001:  stloc.0     
IL_0002:  ldloc.0     
IL_0003:  dup         
IL_0004:  brtrue.s    IL_000C
IL_0006:  pop         
IL_0007:  newobj      UserQuery+MyObj..ctor
IL_000C:  stloc.0     

So it seems the assignment (stloc.0 at IL_000C) is done whether or not myObj was null... but perhaps the JIT optimizes this later.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号