Programming Languages – Why is Type Inference Useful?

programming-languagestype-systems

I read code way more often than I write code, and I'm assuming that most of the programmers working on industrial software do this. The advantage of type inference I assume is less verbosity and less written code. But on the other hand if you read code more often, you'll probably want readable code.

The compiler infers the type; there are old algorithms for this. But the real question is why would I, the programmer, want to infer the type of my variables when I read the code? Isn't it more faster for anyone just to read the type than to think what type is there?

Edit: As a conclusion I understand why it is useful. But in the category of language features I see it in a bucket with operator overloading – useful in some cases but affecting readability if abused.

Best Answer

Let's take a look at Java. Java 8 can't have variables with inferred types. This means I frequently have to spell out the type, even if it is perfectly obvious to a human reader what the type is:

int x = 42;  // yes I see it's an int, because it's a bloody integer literal!

// Why the hell do I have to spell the name twice?
SomeObjectFactory<OtherObject> obj = new SomeObjectFactory<>();

And sometimes it's just plain annoying to spell out the whole type.

// this code walks through all entries in an "(int, int) -> SomeObject" table
// represented as two nested maps
// Why are there more types than actual code?
for (Map.Entry<Integer, Map<Integer, SomeObject<SomeObject, T>>> row : table.entrySet()) {
    Integer rowKey = entry.getKey();
    Map<Integer, SomeObject<SomeObject, T>> rowValue = entry.getValue();
    for (Map.Entry<Integer, SomeObject<SomeObject, T>> col : rowValue.entrySet()) {
        Integer colKey = col.getKey();
        SomeObject<SomeObject, T> colValue = col.getValue();
        doSomethingWith<SomeObject<SomeObject, T>>(rowKey, colKey, colValue);
    }
}

This verbose static typing gets in the way of me, the programmer. Most type annotations are repetitive line-filler, content-free regurgiations of what we already know. However, I do like static typing, as it can really help with discovering bugs, so using dynamic typing isn't always a good answer. Type inference is the best of both worlds: I can omit the irrelevant types, but still be sure that my program (type-)checks out.

While type inference is really useful for local variables, it should not be used for public APIs which have to be unambiguously documented. And sometimes the types really are critical for understanding what's going on in the code. In such cases, it would be foolish to rely on type inference alone.

There are many languages that support type inference. For example:

  • C++. The auto keyword triggers type inference. Without it, spelling out the types for lambdas or for entries in containers would be hell.

  • C#. You can declare variables with var, which triggers a limited form of type inference. It still manages most cases where you want type inference. In certain places you can leave out the type completely (e.g. in lambdas).

  • Haskell, and any language in the ML family. While the specific flavour of type inference used here is quite powerful, you still often see type annotations for functions, and for two reasons: The first is documentation, and the second is a check that type inference actually found the types you expected. If there is a discrepancy, there's likely some kind of bug.

And since this answer was originally written, type inference has become more popular. E.g. Java 10 has finally added C#-style inference. We're also seeing more type systems on top of dynamic languages, e.g. TypeScript for JavaScript, or mypy for Python, which make heavy use of type inference in order to keep the overhead of type annotations manageable.

Related Topic