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.
MyList<int>
Benefit: No boxing and unboxing penalties. 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?
Downcasting. In class-based programming, downcasting or type refinement is the act of casting a reference of a base class to one of its derived classes. In many programming languages, it is possible to check through type introspection to determine whether the type of the referenced object is indeed the one being cast to or a derived type...
Casting does not change the actual object type. Only the reference type gets changed. Upcasting is always safe and never fails. Downcasting can risk throwing a ClassCastException, so the instanceof operator is used to check type before casting.
That's why the downcasting operation is required to be manifest in the text of the program. It's so that you can more easily notice the smell and spend code review attention on it. in what circumstance [s] is it appropriate to write code which downcasts?
In C++, run-time type checking is implemented through dynamic_cast. Compile-time downcasting is implemented by static_cast, but this operation performs no type check. If it is used improperly, it could produce undefined behavior.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With