When is type testing OK?

Assuming a language with some inherent type safety (e.g., not JavaScript):

Given a method that accepts a SuperType, we know that in most cases wherein we might be tempted to perform type testing to pick an action:

public void DoSomethingTo(SuperType o) {
  if (o isa SubTypeA) {
    o.doSomethingA()
  } else {
    o.doSomethingB();
  }
}

We should usually, if not always, create a single, overridable method on the SuperType and do this:

public void DoSomethingTo(SuperType o) {
  o.doSomething();
}

… wherein each subtype is given its own doSomething() implementation. The rest of our application can then be appropriately ignorant of whether any given SuperType is really a SubTypeA or a SubTypeB.

Wonderful.

But, we’re still given is a-like operations in most, if not all, type-safe languages. And that suggests a potential need for explicit type testing.

So, in what situations, if any, should we or must we perform explicit type testing?

Forgive my absent mindedness or lack of creativity. I know I’ve done it before; but, it was honestly so long ago I can’t remember if what I did was good! And in recent memory, I don’t think I’ve encountered a need to test types outside my cowboy JavaScript.

11

“Never” is the canonical answer to “when is type testing okay?”
There’s no
way to prove or disprove this; it is part of a system of beliefs about what
makes “good design” or “good object-oriented design.” It’s also hokum.

To be sure, if you have an integrated set of classes
and also more than one or two functions that need that kind of
direct type testing, you’re probably
DOING IT WRONG. What you really need is a method that’s implemented differently in
SuperType and its subtypes. This is part and parcel of object-oriented
programming, and the whole reason classes and inheritance exist.

In this case, explicitly type-testing is wrong not because type testing is
inherently wrong, but because the language already
has a clean, extensible, idiomatic way of accomplishing type
discrimination, and you didn’t use it. Instead, you fell back to a
primitive, fragile, non-extensible idiom.

Solution: Use the idiom. As you
suggested, add a method to each of the classes, then let standard inheritance
and method-selection algorithms determine which case applies. Or if you can’t
change the base types, subclass and add your method there.

So much for the conventional wisdom, and on to some answers. Some cases where
explicit type testing makes sense:

  1. It’s a one-off. If you had a lot of type discrimination to do,
    you might extend the types, or subclass. But you don’t. You have just
    one or two places where you need explicit testing, so it’s not worth
    your while to go back and work through the class hierarchy to add
    the functions as methods. Or it’s not worth the practical effort to
    add the kind of generality, testing, design reviews, documentation,
    or other attributes of the base classes for such a simple, limited
    usage. In that case, adding a function that does direct testing is rational.

  2. You can’t adjust the classes. You think about subclassing–but you can’t.
    Many classes in Java, for
    instance, are designated final.
    You try to throw in a public class ExtendedSubTypeA extends SubTypeA {...}
    and the compiler tells you, in no uncertain terms, that what you’re doing is
    not possible. Sorry, grace and sophistication of the object oriented model!
    Someone decided you can’t extend their types! Unfortunately, many of the standard library
    are final, and making classes final is common design guidance.
    A function end-run is what’s left available to you.

    BTW, this isn’t limited to statically typed languages. Dynamic language Python has a number of
    base classes that, under the covers implemented in C, cannot really be modified.
    Like Java, that includes most of the standard types.

  3. Your code is external. You are developing with classes and objects that come
    from a range of database servers, middleware engines, and other codebases you can’t
    control or adjust. Your code is just a lowly consumer of objects generated elsewhere.
    Even if you could subclass SuperType, you’re not going to be able to get those
    libraries on which you depend to generate objects in your subclasses. They’re
    going to hand you instances of the types they know, not your variants. This
    isn’t always the case…sometimes they are built for flexibility, and they dynamically
    instantiate instances of classes that you feed them. Or they provide a mechanism to
    register the subclasses you want their factories to construct. XML parsers seem particularly good at
    providing such entry points; see e.g. a JAXB example in Java
    or lxml in Python. But most code bases do not
    provide
    such extensions. They’re going to hand you back the classes they were built with and
    know about. It generally will not make sense to proxy their results into your custom
    results just so you can use a purely object-oriented type selector.
    If you’re going to do type discrimination, you’re going to have to do it
    relatively crudely. Your type testing code then looks quite appropriate.

  4. Poor person’s generics/multiple dispatch. You want to accept a variety of different types to your
    code, and feel that having an array of very type-specific methods isn’t graceful.
    public void add(Object x) seems logical, but not an array of
    addByte, addShort, addInt, addLong,
    addFloat, addDouble, addBoolean, addChar, and addString variants (to
    name a few). Having functions or methods that take a high super-type and then
    determine what to do on a type-by-type basis–they’re not going to win you the
    Purity Award at the annual Booch-Liskov Design Symposium, but
    dropping the Hungarian naming
    will give you a simpler API. In a sense, your is-a or is-instance-of testing
    is simulating generic or multi-dispatch in a language context that doesn’t natively
    support it.

    Built-in language support for both
    generics and
    duck typing reduce the need
    for type checking
    by making “do something graceful and appropriate” more likely. The multiple
    dispatch / interface selection
    seen in languages like Julia and Go similarly replace direct type testing with
    built-in mechanisms for type-based selection of “what to do.”
    But not all languages support these. Java e.g. is generally single-dispatch,
    and its idioms are not super-friendly to duck typing.

    But even with all these type discrimination features–inheritance, generics, duck typing,
    and
    multiple-dispatch–it’s sometimes just convenient to have a single, consolidated
    routine that makes the fact that you are doing something based on the type of the
    object clear and immediate. In metaprogramming
    I have found it essentially unavoidable. Whether falling back to
    direct type inquires constitutes “pragmatism in action” or “dirty coding”
    will depend on your design philosophy and beliefs.

7

The main situation I’ve ever needed it was when comparing two objects, such as in an equals(other) method, which might require different algorithms depending on the exact type of other. Even then, it’s fairly rare.

The other situation I’ve had it come up, again very rarely, is after deserialization or parsing, where you sometimes need it to safely cast to a more specific type.

Also, sometimes you just need a hack to work around third party code you don’t control. It’s one of those things you don’t really want to use on a regular basis, but are glad it’s there when you really need it.

5

The standard (but hopefully rare) case looks like this: if in the following situation

public void DoSomethingTo(SuperType o) {
  if (o isa SubTypeA) {
    DoSomethingA((SubTypeA) o )
  } else {
    DoSomethingB((SubTypeB) o );
  }
}

the functions DoSomethingA or DoSomethingB cannot easily be implemented as member functions of the inheritance tree of SuperType / SubTypeA/ SubTypeB. For example, if

  • the subtypes are part of a library which you cannot change, or
  • if adding the code for DoSomethingXXX to that library would mean to introduce a forbidden dependency.

Note there are often situations where you can circumvent this problem (for example, by creating a wrapper or adapter for SubTypeA and SubTypeB, or trying to re-implement DoSomething completly in terms of basic operations of SuperType), but sometimes these solutions are not worth the hassle or make things more complicated and less extensible than doing the explicit type test.

An example from my yesterdays work: I had a situation where I was going to parallelize the processing of a list of objects (of type SuperType, with exactly two different subtypes, where it is extremely unlikely that there will ever be more). The unparallelized version contained two loops: one loop for objects of subtype A, calling DoSomethingA, and a second loop for objects of subtype B, calling DoSomethingB.

The “DoSomethingA” and “DoSomethingB” methods are both time intensive calculations, using context information which is not available at the scope of the subtypes A and B. (so it makes no sense to implement them as member functions of the subtypes). From the viewpoint of the new “parallel loop”, it makes things a lot easier by dealing with them uniformly, so I implemented a function similar to DoSomethingTo from above. However, looking into the implementations of “DoSomethingA” and “DoSomethingB” shows they work very differently internally. So trying to implement a generic “DoSomething” by extending SuperType with a lot of abstract methods was not really going to work, or would mean to overdesign things completely.

8

As Uncle Bob calls it:

When your compiler forgets about the type.

In one of his Clean Coder episodes he gave an example of a function call that is used to return Employees. Manager is a sub-type of Employee. Let’s assume we have an application service that accepts a Manager‘s id and summons him to office 🙂 The function getEmployeeById() return a super-type Employee , but I want to check if a manager is returned in this use-case.

For example:

var manager = employeeRepository.getEmployeeById(empId);
if (!(manager is Manager))
   throw new Exception("Invalid Id specified.");
manager.summon();

Here I’m checking to see if the employee returned by query is actually a manager (i.e. I expect it to be a manager and if otherwise fail fast).

Not the best example, but it’s uncle Bob after all.

Update

I updated the example as much as I can remember from memory.

4

When is type checking OK?

Never.

  1. By having the behavior associated with that type in some other function, you’re violating the Open Closed Principle, because you’re free to modify the existing behavior of the type by changing the is clause, or (in some languages, or depending on the scenario) because you can’t extend the type without modifying the internals of the function doing the is check.
  2. More importantly, is checks are a strong sign that you’re violating the Liskov Substitution Principle. Anything that works with SuperType should be completely ignorant of what sub types there may be.
  3. You’re implicitly associating some behavior with the type’s name. This makes your code harder to maintain because these implicit contracts are spread throughout the code and not guaranteed to be universally and consistently enforced like actual class members are.

All that said, is checks can be less bad than other alternatives. Putting all common functionality into a base class is heavy-handed and often leads to worse problems. Using a single class that has a flag or enum for what “type” the instance is… is worse than horrible, since you’re now spreading the type system circumvention to all consumers.

In short, you should always consider type checks to be a strong code smell. But as with all guidelines, there will be times when you’re forced to choose between which guideline violation is the least offensive.

26

If you got a large code base (over 100K lines of code) and are close to shipping or are working in a branch that will later have to be merge, and therefore there is a lot cost/risk to changing a lot of cope.

You then sometimes have the option of a large refractor of the system, or some simple localised “type testing”. This creates a technical debt that should be paid back as soon as possible, but often is not.

(It is impossible to come up with an example, as any code that is small enough to be used as an example, is also small enough for the better design to be clearly visible.)

Or in other words, when the aim is to be paid your wage rather than to get “up votes” for the cleanness of your design.


The other common case is UI code, when for example you show a different UI for some types of employees, but clearly you don’t want the UI concepts to escape into all your “domain” classes.

You can you use “type testing” to decide what version of the UI to show, or have some fancy lookup table that converts from “domain classes” to “UI classes”. The lookup table is just a way of hiding the “type testing” in one place.

(Database updating code can have the same issues as UI code, however you tend to only have one set of database updating code, but you can have lots of different screens that must adapt to the type of object being shown.)

4

The implementation of LINQ uses lots of type checking for possible performance optimizations, and then a fallback for IEnumerable .

The most obvious example is probably the ElementAt method (tiny excerpt of .NET 4.5 source):

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index) { 
    IList<TSource> list = source as IList<TSource>;

    if (list != null) return list[index];
    // ... and then an enumerator is created and MoveNext is called index times

But there are lots of places in the Enumerable class where a similar pattern is used.

So perhaps optimizing for performance for a commonly-used subtype is a valid use. I am not sure how this could have been designed better.

2

There is an example that comes up often in games developments, specifically in collision detection, that is difficult to deal with without the use of some form of type testing.

Assume that all game objects derive from a common base class GameObject. Each object has a rigid body collision shape CollisionShape which may provide a common interface (to say query position, orientation, etc) but the actual collision shapes will all be concrete subclasses such as Sphere, Box, ConvexHull, etc. storing information specific to that type of geometric object (see here for a real example)

Now, to test for a collisions I need to write a function for each pair of collision shape types:

detectCollision(Sphere, Sphere)
detectCollision(Sphere, Box)
detectCollision(Sphere, ConvexHull)
detectCollision(Box, ConvexHull)
...

that contain the specific math needed to perform an intersection of those two geometric types.

At each ‘tick’ of my game loop I need to check pairs of objects for collisions. But I only have access to GameObjects and their corresponding CollisionShapes. Clearly I need to know concrete types to know which collision detection function to call. Not even double dispatch (which is logically no different to checking for the type anyway) can help here*.

In practice in this situation the physics engines I’ve seen (Bullet and Havok) rely on type testing of one form or another.

I’m not saying this is necessarily a good solution, it’s just that it may be the best of a small number of possible solutions to this problem

* Technically it is possible to use double dispatch in a horrendous and complicated way that would require N(N+1)/2 combinations (where N is the number of shape types you have) and would only obfuscate what you’re really doing which is simultaneously finding out the types of the two shapes so I don’t consider this to be a realistic solution.

Sometimes you do not want to add a common method to all the classes because it really is not their responsibility to perform that specific task.

For example you want to draw some entities but do not want to add the drawing code directly to them (which makes sense). In languages not supporting multiple dispatch you might end up with the following code:

void DrawEntity(Entity entity) {
    if (entity instanceof Circle) {
        DrawCircle((Circle) entity));
    else if (entity instanceof Rectangle) {
        DrawRectangle((Rectangle) entity));
    } ...
}

This becomes problematic when this code appears at several places and you need to modify it everywhere when adding new Entity type. If that is the case then it can be avoided by using the Visitor pattern but sometimes it is better to just keep things simple and not overengineer it. Those are the situations when type testing is OK.

The only time I use is is in combination with reflection. But even then is dynamic checking mostly, not hard-coded to a specific class (or only hard-coded to special classes such as String or List).

By dynamic checking I mean:

boolean checkType(Type type, Object object) {
    if (object.isOfType(type)) {

    }
}

and not hard-coded

boolean checkIsManaer(Object object) {
    if (object instanceof Manager) {

    }
}

Type testing and type casting are two very closely related concepts. So closely related that I feel confident in saying that you should never do a type test unless your intent is to type cast the object based on the result.

When you think about ideal Object-Oriented design, type testing (and casting) should never happen. But hopefully by now you’ve figured out that Object-Oriented programming is not ideal. Sometimes, especially with lower-level code, the code can’t stay true to the ideal. This is the case with ArrayLists in Java; since they don’t know at run-time what class is being stored in the array, they create Object[] arrays and statically cast them to the correct type.

It’s been pointed out that a common need to type testing (and type casting) comes from the Equals method, which in most languages is supposed to take a plain Object. The implementation should have some detailed checks to make if the two objects are the same type, which requires being able to test what type they are.

Type testing also comes up frequently in reflection. Often you will have methods that return Object[] or some other generic array, and you want to pull out all the Foo objects for whatever reason. This is a perfectly legitimate use of type testing and casting.

In general, type testing is bad when it needlessly couples your code to how a specific implementation was written. This can easily lead to needing a specific test for each type or combination of types, such as if you want to find the intersection of lines, rectangles, and circles, and the intersection function has a different algorithm for each combination. Your goal is to put any details specific to one kind of object in the same place as that object, because that will make it easier to maintain and extend your code.

3

It’s acceptable in a case where you have to make a decision that involves two types and this decision is encapsulated in an object outside of that type hierarchy. For instance, let’s say you’re scheduling which object gets processed next in a list of objects waiting for processing:

abstract class Vehicle
{
    abstract void Process();
}

class Car : Vehicle { ... }
class Boat : Vehicle { ... }
class Truck : Vehicle { ... }

Now let’s say our business logic is literally “all cars get precedence over boats and trucks”. Adding a Priority property to the class doesn’t allow you to express this business logic cleanly because you’ll end up with this:

abstract class Vehicle
{
    abstract void Process();
    abstract int Priority { get }
}

class Car : Vehicle { public Priority { get { return 1; } } ... }
class Boat : Vehicle { public Priority { get { return 2; } } ... }
class Truck : Vehicle { public Priority { get { return 2; } } ... }

The problem is that now to understand the priority ordering you have to look at all the subclasses, or in other words you’ve added coupling to the subclasses.

You should of course make the priorities into constants and put them into a class by themselves, which helps keep scheduling business logic together:

static class Priorities
{
    public const int CAR_PRIORITY = 1;
    public const int BOAT_PRIORITY = 2;
    public const int TRUCK_PRIORITY = 2;
}

However, in reality the scheduling algorithm is something that might change in the future and it might eventually depend on more than just type. For instance, it might say “trucks over a weight of 5000 kg get special priority over all other vehicles.” That’s why the scheduling algorithm belongs in its own class, and it’s a good idea to inspect the type to determine which one should go first:

class VehicleScheduler : IScheduleVehicles
{
    public Vehicle WhichVehicleGoesFirst(Vehicle vehicle1, Vehicle vehicle2)
    {
        if(vehicle1 is Car) return vehicle1;
        if(vehicle2 is Car) return vehicle2;
        return vehicle1;
    }
}

This is the most straightforward way to implement the business logic and still the most flexible to future changes.

1

Type testing is a tool, use it wisely and it can be a powerful ally. Use it poorly and your code will start to smell.

In our software we received messages over the network in response to requests. All deserialized messages shared a common base class Message.

The classes themselves were very simple, just the payload as typed C# properties and routines for marshalling and unmarshalling them (In fact I generated most of the classes using t4 templates from XML description of the message format)

Code would be something like:

Message response = await PerformSomeRequest(requestParameter);

// Server (out of our control) would send one message as response, but 
// the actual message type is not known ahead of time (it depended on 
// the exact request and the state of the server etc.)
if (response is ErrorMessage)
{ 
    // Extract error message and pass along (for example using exceptions)
}
else if (response is StuffHappenedMessage)
{
    // Extract results
}
else if (response is AnotherThingHappenedMessage)
{
    // Extract another type of result
}
// Half a dozen other possible checks for messages

Granted, one could argue that the message architecture could be better designed but it was designed a long time ago and not for C# so it is what it is. Here type testing solved a real problem for us in a not too shabby way.

Worth noting is that C# 7.0 is getting pattern matching (which in many respects is type testing on steroids) it can’t be all bad…

Take a generic JSON parser. The result of a successful parse is an array, a dictionary, a string, a number, a boolean, or a null value. It can be any of those. And the elements of an array or the values in a dictionary can again be any of those types. Since the data is provided from outside your program, you have to accept any result (that is you have to accept it without crashing; you can reject a result that isn’t what you expect).

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật