As programming students, we are taught how to cast types as rote. In none of my courses was I ever taught that casting was necessarily a bad thing. In fact, C++ even has several keywords just for casting. Casting was just something one had to do in order to look at a variable or object in a different manner. I expect some of the books I have read probably subtly suggested curtailing casting, but for the most part, casting was generally considered fine. (Or maybe they were not that subtle and I just wasn’t getting the point!)
Gradually through my own experience, I have begun to form the opinion that casting is never an ideal solution, but there are times when it’s all but unavoidable. At very least, before writing a cast, it should be carefully thought through.
When changing primitives to other primitive types, I tend to use library functions instead of casts. Library functions are more explicit in their meaning. For example:
float f = 2.5F;
int i = (int)f;
will cause data to be lost. Most, if not all languages, will cut the .5 off and leave i equal to 2. I’d rather make it obvious:
float f = 2.5F;
int i = Math.floor(f);
Now it’s clear what I’m trying to do. If I want to round the value instead of truncating the decimal, I’ll use Math.round().
Let’s establish a couple of classes to use for the next sections: Vehicle is a superclass, and Truck subclasses it.
Upcasting is the casting from a specific to a more general type higher in the type hierarchy (i.e. to a parent class). When would you want to do this? One reason is if the subclass has overridden a virtual method and you want to be specific about which one you call. Upcasting is fine in this case. However, if you are calling a superclass method, the cast is redundant. Leave it out.
Let’s give both our Vehicle and Truck classes a virtual method called drive().
var v = new Vehicle();
var t = new Truck();
v.drive(); // Calls Vehicle's drive method
t.drive(); // Calls Truck's drive method
((Vehicle)t).drive(); // Calls Vehicle's drive method
While a little odd, you might have a perfectly legitimate reason for doing this.
Downcasting is where it starts to get ugly. When you attempt to cast to a subclass, of which your object may not even be the correct type, you get some real ugly code, or worse: class cast exceptions.
((Truck)v).drive(); // Compiles fine. Throws class cast exception
So what do you do if you have a Vehicle object, that you think is a Truck object and you want to call Truck methods on it? How about this:
void method(Vehicle v)
if (v instanceof Truck)
Ugggh, there’s that ugly cast. Yes it works, and it will compile just fine, but there’s absolutely no protection. Those two lines aren’t tied together in any way. I can change the first to ‘v instanceof SUV’ and I’m back to my class cast exceptions again. You may want to rework how you are approaching your problem. Why are you passing to your method a vehicle object that might be a truck? This is a code smell.
My advice: if you are tempted to cast a variable or object, stop and think if you are approaching the problem correctly. You might be. But you probably aren’t.