C# · Dotnet

Generics and Default goes a bit tricky [TIP]

Dear Reader,

Today i was just reading about default keyword, i am sure you might have read about it alot in various places. As per that, the default keyword just initializes the LHS to a RHS types default value i.e: if RHS type is a reference type, then null is assigned other wise 0 is assigned unless its not a struct.

So i started to get a bit curious and started to dig a bit deeper into IL and see what actually the compiler is upto. So upon looking at the IL, it looked as: (Below IL is for default usage over a generic parameter)

IL_0000: nop
IL_0001: ldarga.s ‘value’
IL_0003: initobj !T
IL_0009: ret

As you can see the compiler has become smart (i was surprised to see how compiler team went a bit smart here) in using initobj opcode. If you happen to check out its description in MSDN, it says that its used to initialize only value type to either 0 or null reference. So at first it looks weird, that its only for value types, but when you pass the T type as reference type how on earth run time knows that the type is actually ref type and not value type to do initobj.

But you know the trick here is that if you happen to use NewObj Opcode for reference type in the IL, then things would go chaos, because as per its definition, NewObj Opcode shall initializes the type by calling its ctor. But in this case, the specification says that for reference type a value Null is assigned. So if you pass T as reference type, it just assigns Null at run time.

On the other hand, if you happen to use default keyword on non generic parameter say a reference type then the compiler just replaces default keyword with ldNull Opcode.

Now let me come back to the generics code. There is a bit craziness goes on with default and generics internally. Now by mistake if a developer writes code like this and he does not know about default keyword:

class MyClass<T>
{
void Hello(T TValue)
{
if (TValue == null)
;//Do some thing.
}
}

Here actually the compiler places a box Opcode in IL for TValue before comparing with Null as shown:

IL_0000: nop
IL_0001: ldarg.1
IL_0002: box !T
IL_0007: ldnull
IL_0008: ceq
IL_000a: ldc.i4.0
IL_000b: ceq
IL_000d: stloc.0
IL_000e: ldloc.0
IL_000f: brtrue.s IL_0011

As you can see from the above IL, not only the number of IL instructions is more, even there is a Box OpCode being placed. If your passing a reference type, then the run time does not waste time in converting it again, but rather checks and moves on. So you can say that there is a very lil bit of performance over head. But if by chance your code has not put any generic constraints, then passing value types do put alot of overhead in performance because the boxing happens. Either ways, there is a performance overhead with the code, and its nice that .NET has provided us much better way to deal with it and in this case to use default(T) which does not have much performance overheads as above.

Thanks

P.S: I wish i could write some thing better than this, if you have suggestions, please do comment.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s