I have always wondered why Java does not do type inference given that the language is what it is, and its VM is very mature. Google's Go is an example of a language with excellent type inference and it reduces the amount of typing one has to do. Is there any special reason behind this feature not being a part of Java?
Java Type Systems – Why Java Does Not Use Type Inference
data typesjavaprogramming-languagestype-systems
Related Solutions
Your example is in some way a special case. In a non trivial program you can typically not determine the class of the object a certain reference points to better than "it is of the type the reference was declared for or a subtype of it".
The whole concept of polymorphism is based on the fact that the concrete class is only known at runtime but not at compile time. This of course means that the compiler must ensure that the methods that are called on a reference will be available on the referenced object at runtime. The only methods for which this holds true are the methods of the class for which the variable was declared (including all inherited methods from the super classes).
EDIT
As @David said in his comment the reason behind this is that typing is done statically by the programmer in java. If java had type inference the typing would be done by the compiler (but still statically) and your example would be absolutely valid. But it could be invalidated by another line doing this ob = new A()
.
If java were a dynamic typed language the compiler wouldn't care at all (at compile time) what methods you call on an object.
First, the GHC error,
GHC is attempting to unify a few constraints with x
, first, we use it as a function so
x :: a -> b
Next we use it as a value to that function
x :: a
And finally we unify it with the original argument expression so
x :: (a -> b) -> c -> d
Now x x
becomes an attempt to unify t2 -> t1 -> t0
, however, We can't unify this since it would require unifying t2
, the first argument of x
, with x
. Hence our error message.
Next, why not general recursive types. Well the first point worth noting is the difference between equi and iso recursive types,
- equi-recursive are what you'd expect
mu X . Type
is exactly equivalent to expanding or folding it arbitrarily. - iso-recursive types provide a pair of operators,
fold
andunfold
which fold and unfold the recursive definitions of types.
Now equi-recursive types sound ideal, but are absurdly hard to get right in complex types systems. It can actually make type checking undecidable. I'm not familiar with every detail of OCaml's type system but fully equirecursive types in Haskell can cause the typechecker to loop arbitrarily trying to unify types, by default, Haskell makes sure that type checking terminates. Further more, in Haskell, type synonyms are dumb, the most useful recursive types would be defined like type T = T -> ()
, however are inlined almost immediately in Haskell, but you can't inline a recursive type, it's infinite! Therefore, recursive types in Haskell would demand a huge overhaul to how synonyms are handled, probably not worth the effort to put even as a language extension.
Iso-recursive types are a bit of a pain to use, you more or less have to explicitly tell the type checker how to fold and unfold your types, making your programs more complex to read and write.
However, this is very similar to what your doing with your Mu
type. Roll
is fold, and unroll
is unfold. So actually, we do have iso-recursive types baked in. However, equi-recursive types are just too complex so systems like OCaml and Haskell force you to pass recurrences through type level fixpoints.
Now if this interests you, I'd recommend Types and Programming Languages. My copy is sitting open in my lap as I'm writing this to make sure I've got the right terminology :)
Best Answer
Technically speaking, Java does have type inferencing when using generics. With a generic method like
The compiler will analyze and understand that when you write
A String is going to be returned for the first call and an Integer for the second call based on what was input as an argument. You will get the proper compile-time checking as a result. Additionally, in Java 7, one can get some additional type inferencing when instantiating generics like so
Java is kind enough to fill in the blank angle brackets for us. Now why doesn't Java support type inferencing as a part of variable assignment? At one point, there was an RFE for type inferencing in variable declarations, but this was closed as "Will not fix" because
The contributor who closed this also noted that it just feels "un-java-like", which I am one to agree with. Java's verbosity can be both a blessing and a curse, but it does make the language what it is.
Of course that particular RFE was not the end of that conversation. During Java 7, this feature was again considered, with some test implementations being created, including one by James Gosling himself. Again, this feature was ultimately shot down.
With the release of Java 8, we now get type inference as a part of lambdas as such:
The Java compiler is able to look at the method
Collections#sort(List<T>, Comparator<? super T>)
and then the interface ofComparator#compare(T o1, T o2)
and determine thatfirst
andsecond
should be aString
thus allowing the programmer to forgo having to restate the type in the lambda expression.