A recent comment to my answer suggested that a variable is created twice.
At first, I started writing the following comment:
I'm pretty sure .NET's JIT compiler will rewrite the code by moving the declarations of both variables to the place they are actually used. [...]
But then I decided to check my claims. To my surprise, it looks that I'm plainly wrong.
Let's start with the following piece of code:
class Something
{
public string text;
public int number;
public Something(string text, int number)
{
Console.WriteLine("Initialized {0}.", number);
this.text = text;
this.number = number;
}
}
static void Display(Something something)
{
Console.WriteLine(something.text, something.number);
}
static int x = 0;
public static void Main()
{
var first = new Something("Hello, {0}!", 123);
var second = new Something("World, {0}!", 456);
Display(x > 0 ? first : second);
}
Warning: the code is a POC and has severe style issues such as public fields; don't write code like this outside prototypes.
The output is the following:
Initialized 123.
Initialized 456.
World, 456!
Let's change the Main()
method a bit:
void Main()
{
Display(
x > 0 ?
new Something("Hello, {0}!", 123) :
new Something("World, {0}!", 456));
}
Now the output becomes:
Initialized 456.
World, 456!
By the way, if I look at IL of the modified version, both newobj
instructions are still there:
IL_0000: ldarg.0 IL_0001: ldarg.0 IL_0002: ldfld UserQuery.x IL_0007: ldc.i4.0 IL_0008: bgt.s IL_001B IL_000A: ldstr "World, {0}!" IL_000F: ldc.i4 C8 01 00 00 IL_0014: newobj UserQuery+Something..ctor IL_0019: br.s IL_0027 IL_001B: ldstr "Hello, {0}!" IL_0020: ldc.i4.s 7B IL_0022: newobj UserQuery+Something..ctor IL_0027: call UserQuery.Display IL_002C: ret
This means that the compiler left both initialization instructions untouched, but JIT optimized them by keeping only one.
What is the reason JIT doesn't optimize the original piece of code by removing the unused variable and its assignment?