Silent Boxing

Here is an innocent piece of code for you. Can you spot if there is anything wrong with it?

using System;

namespace SilentBoxing
    class EntryPoint
        static void Main(string[] args)
            double d = 25.5;
            Console.WriteLine("You set d to be {0}", d);
            Console.WriteLine("If you add 5 to d, it will become " + (d + 5));

It compiles and runs as expected, however, there is something wrong with it. As you may have guessed from the title of this blog post, this code requires boxing. Times two. The boxing occurs in the calls to Console.WriteLine. First time we call WriteLine, the compiler resolves the call to

Console.WriteLine (String, Object[])

Note that the array of parameters is of type Object. Thus the double d is boxed into an object.

The second type boxing occurs is in the second call to WriteLine, which is resolved with the following overload:

Console.WriteLine (String)

Since we are creating the string on the fly, the (d+5) expression is boxed into an object and concatenated with the string.

Boxing of value types is something to watch out for. It is undesirable because it pollutes the managed heap. A boxed value type requires allocating memory on the managed heap to contain the value and its type, since objects on the heap get allocated a type object containing, among other things, the type object pointer and the sync block index. The type object pointer is what allows two or more reference types to point to the same object. The sync block index is used to synchronise access to a reference type from difference threads. None of this great functionality is required within our WriteLine calls.

So, how can we eliminate the need for boxing? Below is the code without it, and it is done with the use of ToString() method. System.Double.ToString overrides ToString() from System.ValueType parent. It returns a string and does not cause boxing. Note that calling ToString() on most build-in types does not cause boxing. If you write your own struct, consider overriding ToString() to avoid potential performance downgrade.

// ...
Console.WriteLine("You set d to be {0}", d.ToString());                       // No more boxing!
Console.WriteLine("If you add 5 to d, it will become " + (d + 5).ToString()); // No more boxing!
// ...