tags:

views:

227

answers:

3

Just trying to get my head around Generics by reading this enlightening article by Juval Lowy

Paraphrasing.. When you define a Generic class definition, it is compiled into IL.

  • For value-types, as soon as you request for a specific value-type, it substitutes the T with your specific value type to obtain the IL for that specific configuration e.g. MyList<int> Benefit: No boxing and unboxing penalties.
  • All good.. for reference types, the compiler replaces all instances of T in your definition with Object and creates the IL which is used for all ref types. Instances however are allocated based on the actual requested ref type e.g. MyList<String>

Now pre-generics we could have written methods that take Object parameters. Generics claims 100% performance improvement because 'it avoids the performance penalty you incur when you downcast the object type to your specific type when you want to use it'

 // assume GetItem returns an Object
 string sMyPreciousString = (string) obList.GetItem();

What is this performance hit when you downcast from Object to specific reference type? Also it seems like up-casting to Object (even Generics would do this) isn't a performance hit.. why?

+3  A: 

Upcasting to object doesn't require an execution time check - it will always work, and is just a no-op basically.

Downcasting requires an execution time check to make sure you're not casting a Stream to a String for example. It's a pretty small penalty, and very unlikely to be a bottleneck - but avoiding it is just one extra benefit for generics.

Jon Skeet
Simple when you know it... a simple IL instr isinst for a 100% perf improvement :)
Gishu
+1  A: 

The performance hit comes from the need for a run time type check. If B is a subclass of A, then when you cast a B into an A, you know at compile time that it will be safe, since all Bs are As. Therefore, you do not need to generate any runtime code to check the type.

However, when you cast an A into a B, you do not know at compile time whether the A is actually a B or not. It might just be an A, it might be of type C, a different subtype of A. Therefore, you need to generate runtime code that will make sure the object is actually a B and throw an exception if it isn't.

Generics don't have this problem, because the compiler knows, at compile time, that only Bs were put into the data structure, so when you pull something out, the compiler knows that it will be a B, so there's no need for the type check at run time.

Glomek
+1  A: 

Reading up on the IL that gets generated (this article mentions it)... aha - isinst.

If you weren't downcasting, you wouldn't have to call isinst.

David B