Ever since I heard of type inference (in Haskell), I lived under the impression that Java is the exact opposite, i.e., it has no type inference. Recently though, I had an aha moment and realized that Java employs type inference in its generics implementation.
Then, I read two papers by Gilad Bracha (one of the people behind the generics implementation in Java, as far as I understand). The first paper is a tutorial about generics (PDF), in which he explicitly says that the compiler will infer the actual type argument used to replace the format type parameter. So, there’s type inference in Java, but why only for generics, why not something like C#’s var keyword? And this is my question to you.
Why doesn’t Java has more type inference built into the compiler?
I will suggest an answer though, and this is related to the second paper that I read, Pluggable Type Systems (PDF). It seems, Gilad Bracha believes that the inference part shouldn’t be part of the compiler, but an IDE feature or similar (section 4, paragraph 6 in the above mentioned paper):
A better engineering approach is to
implement type inference as a separate
tool, available in the IDE.
Programmers who find entering type
annotations tiresome can invoke an
inferencer on demand.
What do you think?
Well, I think type inference is in Java for historical reasons mostly: as befits a language with strong legacy constraints, Java improvements are made cautiously & incrementally (as the JCP shows, even though some improvements of type inference manage to go through). With generics, the long-standing GJ implementation was thoroughly evaluated before inclusion in Java 5.
But that does not mean that there is a strong culture for pervasive type inference in Java. As per the spec:
I do think more type inference for Java would be a boon (Scala is already a very interesting improvement in that direction). IMHO, type inference makes the feedback loop with the type checker less mechanical, while being just as sound, letting you write less types, but making you type-check just as much. Since a major benefit of types is to direct the mental process of program search (“letting you write within the space of well-typed programs, rather than in the space of ascii turds“), this comfort in interaction with the type checker seems invaluable : you get to have a type-checker that verifies you think in well-typed terms and trains you to do so, rather than making you account for it on every line.
Now, the stage at which type inference should happen is another question. I think wanting to have “inferencers” separate from the runtime answers legacy concerns : it avoids requiring you to have a type inference algorithm that is always backwards-compatible. But the key then becomes what your standard/major libraries look like : is the source you publish & exchange with others annotated or not ?
While it’s true that an annotated source can, valuably, be type-checked whatever the strength of your inference engine is, I’d still want a type inferencer in the compiler, because it’s not only that I don’t want to write
List<CacheDecoratorFactory> cacheDecoratorFactories = new ArrayList<CacheDecoratorFactory>();, it’s that I don’t event want to read it. Nor do I want to deal with it when I refactor pre-existing source, for that matter. I would need a type “hider” erasing annotations before I interact with source, but if the type inference engine is not complete, the problem of which annotations to erase, and ensuring the erasure followed by type reconstruction is bijective becomes thorny (esp. if your inference engine doesn’t return a principal type) … If we have to solve a thorny problem anyway, why not make it a good, and as-complete-as-possible type inference algorithm ? My hunch is that past a certain level of quality (particularly in the generality of the returned types), the legacy concerns would start to fade.