Is the c# compiler smarter than the VB.NET compiler?
Asked Answered
T

2

11

If I look at the IL that is created in Linqpad for the two following code snippets, I wonder what happens here.

In c#

int i = 42;

results in the following IL code

IL_0000:  ret

whereas in VB

Dim i As Integer = 42

it is

IL_0000:  ldc.i4.s    2A 
IL_0002:  stloc.0  

Apparently, the c# compiler understands the the value is never used and thus simply returns nothing. In VB.NET the actual code is translated.

Is that due to differences in compiler optimization or is there anything else at work?

Update: Just to clarify this - I just enter this one line into LinqPad and look at the IL it creates (most definitely by running the respective compiler). There is no program.

Tetartohedral answered 9/2, 2012 at 10:55 Comment(6)
I believe that the C# compiler performs more optimizations, at present (this will almost certainly change when Roslyn comes in). But in this case, it's a bit of a false win for the C# compiler, since it will almost certainly be optimized by the JIT compiler anyway.Nosy
@AakashM: As I write, this is all I enter into LinqPad.There is no other code. LinqPad produces IL by compiling in the background.Tetartohedral
Does it compiles to the same in C# in debug? I assume that C# optimizes more when it's in release mode then VB.NET. That's one reason why you cannot evaluate variables in release in C# that aren't used while you can in VB.NET. I prefer the latter.Subsoil
@Tim: I'm not compiling at all - this is just a LinqPad IL result.Tetartohedral
LINQPad invokes CodeDomProviders for C# and VB which thunk to the CSC.exe and VB compilers. Hence the fidelity in the IL translations. You can enable/disable compilers optimizations in Edit | Preferences (or with a button on the status bar in the recent betas).Hankypanky
@Joe: Indeed, with "Optimize queries" turned to false the IL code is the same. Makes me wonder how those queries are optimized (is it just the /optimize switch?). And yet, as AakashM proved, even the assembly code differs.Tetartohedral
C
10

Taking away the linqpad question, I ran vbc and csc with /optimize+ /debug- on these programs:

Module f

Public Sub Main()
    Dim i As Integer = 42
End Sub

End Module

and

public static class f
{

public static void Main()
{
    int i = 42;
}

}

and got these CIL results from ILDASM:

For the VB:

.method public static void  Main() cil managed
{
  .entrypoint
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       4 (0x4)
  .maxstack  1
  .locals init (int32 V_0)
  IL_0000:  ldc.i4.s   42
  IL_0002:  stloc.0
  IL_0003:  ret
} // end of method f::Main

For the C#:

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       1 (0x1)
  .maxstack  8
  IL_0000:  ret
} // end of method f::Main

So, yes, at least in this respect csc is 'smarter' than vbc. But I bet the JITter would remove any difference at execution time.

edit

I checked, and actually the executed native code is different, at least on my system. I put in Console.ReadLine() calls in both to give me a chance to attach a debugger, and I got these disassemblies:

From the VB:

00000000  sub         rsp,38h 
00000004  mov         dword ptr [rsp+20h],0 
0000000c  mov         rax,7FF000434D8h 
00000016  mov         eax,dword ptr [rax] 
00000018  test        eax,eax 
0000001a  je          0000000000000021 
0000001c  call        FFFFFFFFE45BA230 
00000021  mov         dword ptr [rsp+20h],2Ah 
00000029  call        FFFFFFFFE26ABF20 
0000002e  mov         qword ptr [rsp+28h],rax 
00000033  nop 
00000034  jmp         0000000000000036 
00000036  add         rsp,38h 
0000003a  ret 

From the C#:

00000000  sub         rsp,38h 
00000004  mov         rax,7FF000534D8h 
0000000e  mov         eax,dword ptr [rax] 
00000010  test        eax,eax 
00000012  je          0000000000000019 
00000014  call        FFFFFFFFE45AA230 
00000019  call        FFFFFFFFE391BF20 
0000001e  mov         qword ptr [rsp+20h],rax 
00000023  nop 
00000024  jmp         0000000000000026 
00000026  add         rsp,38h 
0000002a  ret 

Now, my assembley is pretty much non-existent, but even I can see that

mov         dword ptr [rsp+20h],2Ah 

in the from-VB refers to a constant value of hex 2A, which is 42 decimal. So there you go, it does execute more instructions in the end.

Cobbett answered 9/2, 2012 at 11:10 Comment(1)
well we also have a larger stack as in 8 (C#) vs 1Melindamelinde
O
1

I think in C# case the compiler does the memory allocation part and saving value of int in one step and in VB case DIM statement is first step which just allocates memory and then the value is save on the second step. DIM is generic and is used with all data types so it might be something like one step extra in all cases. Thoughts?

Ocieock answered 9/2, 2012 at 11:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.