Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differences between how C# and VB handle named parameters?

Now that C# supports named parameters, I was checking to see if it was implemented the same way VB did it, and found that there is a slight difference. Take for example a library function like this:

public static void Foo(string a, string b)
{
    Console.WriteLine(string.Format("a: {0}, b: {1}", a, b));
}

In C#, if you call it like this:

Foo(a: "a", b: "b");

The compiler produces the following IL instructions:

.locals init (
    [0] string CS$0$0000,
    [1] string CS$0$0001)
L_0000: nop 
L_0001: ldstr "a"
L_0006: stloc.0 
L_0007: ldstr "b"
L_000c: stloc.1 
L_000d: ldloc.0 
L_000e: ldloc.1 
L_000f: call void [TestLibrary]TestLibrary.Test::Foo(string, string)
L_0014: nop 
L_0015: ret 

Which translates to the following C# code:

string CS$0$0000 = "a";
string CS$0$0001 = "b";
Test.Foo(CS$0$0000, CS$0$0001);

In VB, if you call it like this:

Foo(a:="a", b:="b")

The compiler produces the following IL instructions:

L_0000: nop 
L_0001: ldstr "a"
L_0006: ldstr "b"
L_000b: call void [TestLibrary]TestLibrary.Test::Foo(string, string)
L_0010: nop 
L_0011: nop 
L_0012: ret 

Which translates to the following VB code:

Foo("a", "b");

The way VB does it requires much fewer instruction calls, so is there any advantage to the way C# implements it? If you don't use the named parameters, C# produces the same thing as VB.


EDIT: Now that we've determined that the extra instructions go away in release mode, is there a particular reason for them to be present in debug mode? VB acts the same in both modes, and C# doesn't insert the extra instructions when calling the method normally without named parameters (including when you use optional parameters).

like image 555
Greg Shackles Avatar asked Feb 25 '10 04:02

Greg Shackles


People also ask

How C and C++ is different?

Conclusion. In a nutshell, the main difference between C and C++ is that C is a procedural with no support for objects and classes, whereas C++ is a combination of procedural and object-oriented programming languages.

How is Cplus different from sea?

KEY DIFFERENCEC is a Procedural Oriented language, whereas C++ is an Object-Oriented Programming language. C supports only Pointers whereas C++ supports both pointers and references. C does not allow you to use function overloading whereas C++ allows you to use function overloading.

Are C and C++ the same?

C++ is a superset of C, so both languages have similar syntax, code structure, and compilation. Almost all of C's keywords and operators are used in C++ and do the same thing. C and C++ both use the top-down execution flow and allow procedural and functional programming.

How is C++ better than C?

Compared to C, C++ has significantly more libraries and functions to use. If you're working with complex software, C++ is a better fit because you have more libraries to rely on. Thinking practically, having knowledge of C++ is often a requirement for a variety of programming roles.


2 Answers

is there a particular reason for them to be present in debug mode?

The difference is between:

  • push a temporary value on the stack, use it, discard it, and
  • store a temporary value into a specific stack slot, make a copy of it onto the stack, use it, discard it, but the original copy of the temporary value stays in the stack slot

The visible effect of this difference is that the garbage collector cannot be as aggressive about cleaning up the value. In the first scenario, the value could be collected immediately once the call returns. In the second scenario, the value is only collected after the current method returns (or the slot is re-used).

Making the garbage collector less aggressive often helps in debug scenarios.

The implied question is:

Why the difference between C# and VB?

The C# and VB compilers were written by different people who made different choices about how their respective code generators work.

UPDATE: Re: your comment

In the C# compiler, the unoptimized IL generation is essentially of the same structure as our internal representation of the feature. When we see a named argument:

M(y : Q(), x : R());

where the method is, say

void M(int x, int y) { }

we represent this internally as though you'd written

int ytemp = Q();
int xtemp = R();
M(xtemp, ytemp);

Because we want to preserve the left-to-right evaluation of the side effects of Q and R. This is a reasonable internal representation, and when we codegen it in non-optimized mode, we just codegen the code directly from the internal representation with hardly any modifications.

When we run the optimizer we detect all kinds of stuff -- such as the fact that no one uses those invisible local variables for anything. We can then eliminate the locals from the codegen.

I know very little about the VB internal representation; I haven't worked on the VB compiler since 1995, and I hear that it might have changed just slightly in the last fifteen years. I would imagine that they do something similar, but I don't know the details of how they represent named parameters or how their code generator deals with them.

My point is that this difference does not, to my knowledge, illustrate an important semantic difference. Rather, it illustrates that the nonoptimized build just spits out whatever high-level internal representation we happened to generate that we know has the desired semantics.

like image 161
Eric Lippert Avatar answered Oct 26 '22 23:10

Eric Lippert


The compiler produces the following C# code:

No - the compiler produces IL, which you are then translating to C#. Any resemblence to C# code is purely accidental (and not all the generated IL can be written as C#). The presence of all those "nop" tells me you're in "debug" mode. I would retry in "release" mode - it can make a big difference to these things.

I fired it up in release mode, using:

static void Main()
{
    Foo(a: "a", b: "b");
}

Giving:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 8
    L_0000: ldstr "a"
    L_0005: ldstr "b"
    L_000a: call void ConsoleApplication1.Program::Foo(string, string)
    L_000f: ret 
}

So identical.

like image 38
Marc Gravell Avatar answered Oct 26 '22 23:10

Marc Gravell