Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does implicitly calling toString on a value type cause a box instruction

Tags:

performance

c#

This is more a 'wonder why' than a specific issue but look at the following code

        static void Main(string[] args)
        {
            int val = 10;

            Console.WriteLine("val is {0}", val); // (1)
            Console.WriteLine("val is {0}", val.ToString()); //(2)


        }

In case (1) the following IL is output

IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  stloc.0
  IL_0004:  ldstr      "val is {0}"
  IL_0009:  ldloc.0
  IL_000a:  box        [mscorlib]System.Int32
  IL_000f:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)

In case (2) where I explicitly call the toString method I get

IL_0014:  nop
  IL_0015:  ldstr      "val is {0}"
  IL_001a:  ldloca.s   val
  IL_001c:  call       instance string [mscorlib]System.Int32::ToString()
  IL_0021:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)

So in case (1), even though int overrides toString, the value type is boxed and the toString method is called which presumably then calls the vtable override

So the result is exactly the same but an explicit toString avoids a boxing operation

Anyone know why?

=Edit=
OK to be clear, what's confusing me is that I'm starting with the assumption that even though int derives from System.ValueType, that in turn derives from System.Object because it contains toString, GetHashCode etc.
So in my naive view ( probably from C++), if I override a method derived from System.Object then there is no need to cast to System.Object ( and hence box the value type ) because an overriden method exists and the compiler will automatically reference the vtable entry for the type.
I'm also assuming that calling Console.WriteLine() implicitly calls int.toString so perhaps that's where I'm going wrong. Hope that makes sense

OK - all sorted. Thanks all for setting me straight. All to do with a bad assumption of mine that Console.WriteLine was doing an implicit string conversion. Don't ask me why I thought that - seems blindingly obvious how wrong that is now :)

like image 535
zebrabox Avatar asked Aug 31 '09 23:08

zebrabox


1 Answers

You are not implicitly calling ToString at all. The is no overload of the WriteLine method that takes strings after the format string, it only takes objects.

So, you are not implicitly calling ToString, you are implicitly converting the int to object. The first case is equivalent to:

Console.WriteLine("val is {0}", (object)val);

As the int is a value type, boxing occurs.

The second case is equivalent to:

Console.WriteLine("val is {0}", (object)val.ToString());

As the string is a reference type, casting it to object doesn't actually cause any code to be emitted. It just matches the type with the method signature.

like image 140
Guffa Avatar answered Oct 11 '22 04:10

Guffa