Type casting is a very useful technique when there is no time or desire to think and design objects properly. Type casting (or class casting) helps us work with provided objects differently, based on the class they belong to or the interface they implement. Class casting helps us discriminate against the poor objects and segregate them by their race, gender, and religion. Can this be a good practice?
This is a very typical example of type casting (Google Guava is full of it, for example
sizeOf() method calculates the size of an iterable. However, it is smart enough to understand that if
items are also instances of
Collection, there is no need to actually iterate them. It would be much faster to cast them to
Collection and then call method
size(). Looks logical, but what's wrong with this approach? I see two practical problems.
First, there is a hidden coupling of
Collection. This coupling is not visible to the clients of
sizeOf(). They don't know that method
sizeOf() relies on interface
Collection. If tomorrow we decide to change it,
sizeOf() won't work. And we'll be very surprised, since its signature says nothing about this dependency. This won't happen with
Collection, obviously, since it is part of the Java SDK, but with custom classes, this may and will happen.
The second problem is an inevitably growing complexity of method
sizeOf(). The more special types it has to treat differently, the more complex it will become. This if/then forking is inevitable, since it has to check all possible types and give them special treatment. Such complexity is a result of a violation of the single responsibility principle. The method is not only calculating the size of
Iterable but is also performing type casting and forking based on that casting.
What is the alternative? There are a few, but the most obvious is method overloading (not available in semi-OOP languages like Ruby or PHP):
Isn't that more elegant?
Philosophically speaking, type casting is discrimination against the object that comes into the method. The object complies with the contract provided by the method signature. It implements the
Iterable interface, which is a contract, and it expects equal treatment with all other objects that come into the same method. But the method discriminates objects by their types. The method is basically asking the object about its ... race. Black objects go right while white objects go left. That's what this
instanceof is doing, and that's what discrimination is all about.
instanceof, the method is segregating incoming objects by the certain group they belong to. In this case, there are two groups: collections and everybody else. If you are a collection, you get special treatment. Even though you abide by the
Iterable contract, we still treat some objects specially because they belong to an "elite" group called
You may say that
Collection is just another contract that an object may comply with. That's true, but in this case, there should be another door through which those who work by that contract should enter. You announced that
sizeOf() accepts everybody who works on the
Iterable contract. I am an object, and I do what the contract says. I enter the method and expect equal treatment with everybody else who comes into the same method. But, apparently, once inside the method, I realize that some objects have some special privileges. Isn't that discrimination?
To conclude, I would consider
instanceof and class casting to be anti-patterns and code smells. Once you see a need to use them, start thinking about refactoring.