Any reason why Java shouldn't allow generic type declarations on a variable declaration?

generics, java, language-design

Solution

Basically, type variables can only currently have two scopes in Java: 1) class scope, or 2) method scope. You're asking, why not allow another scope -- scope of a local block of code (in this case, the inside of a for loop.

Yes, in some cases this would be helpful. And it would be not too hard to add it to the language. However, these are pretty rare cases, and is more likely to confuse people than help. Also, a relatively simple and effective workaround exists, as you have already discovered -- move that local block scope to a private helper function, which can then use a method-scope type variable:

public void resetFoos(Iterable<Foo<?>> foos) {
    for (Foo<?> foo : foos) {
        resetFoo(foo);
    }
}

private <T> void resetFoo(Foo<T> foo) {
    foo.setValue(foo.getValue());
}

Yes, this might make the code less efficient by making extra method calls, but that is a minor concern.

Problem

Suppose we have a class like this: ``` public class xx { public interface Foo<T> { T getValue(); void setValue(T value); } public void resetFoos(Iterable<Foo<?>> foos) { for (Foo<?> foo : foos) foo.setValue(foo.getValue()); } } ``` It will fail to compile even though intuitively it seems like it "should": ``` xx.java:10: setValue(capture#496 of ?) in xx.Foo<capture#496 of ?> cannot be applied to (java.lang.Object) foo.setValue(foo.getValue()); ``` The reason is that `foo` does not have a bound generic type, so the compiler doesn't "know" that the output of `foo.getValue()` is compatible with the input of `foo.setValue()`. So to fix this you have to create a new method just for the purpose of binding the generic type parameter in the `for()` loop: ``` public class xx { public interface Foo<T> { T getValue(); void setValue(T value); } public void resetFoos(Iterable<Foo<?>> foos) { for (Foo<?> foo : foos) this.resetFoo(foo); } // stupid extra method here just to bind <T> private <T> void resetFoo(Foo<T> foo) { foo.setValue(foo.getValue()); } } ``` This has always annoyed me. Plus, it seems like there can be a simple solution. My question: Is there any "good" reason why the java language shouldn't be extended to allow generic type declarations on variable declarations? For example: ``` public class xx { public interface Foo<T> { T getValue(); void setValue(T value); } public void resetFoos(Iterable<Foo<?>> foos) { for (Foo<?> foo : foos) { final <T> Foo<T> typedFoo = foo; foo.setValue(foo.getValue()); } } } ``` or, more concisely in this case of a `for()` loop: ``` public class xx { public interface Foo<T> { T getValue(); void setValue(T value); } public void resetFoos(Iterable<Foo<?>> foos) { for (<T> Foo<?> foo : foos) foo.setValue(foo.getValue()); } } ``` I'm wondering if some compiler wizard can explain why this would either be too hard, or can (and should) be done. EDIT: In response to this suggested solution: ``` public <T> void resetFoos(Iterable<Foo<T>> foos) { for (Foo<T> foo : foos) { foo.setValue(foo.getValue()); } } ``` This method signature doesn't allow `Foo`s with various generic types to be reset together. In other words, trying to pass in an `Iterable<Foo<?>>` causes a compile error. This example demonstrates the problem: ``` public static class FooImpl<T> implements Foo<T> { private T value; public FooImpl(T value) { this.value = value; } @Override public T getValue() { return value; } @Override public void setValue(T value) { this.value = value; } } public static <T> void resetFoos(Iterable<Foo<T>> foos) { for (Foo<T> foo : foos) { foo.setValue(foo.getValue()); } } public static void main(String[] args) { final Foo<Object> objFoo = new FooImpl<>(new Object()); final Foo<Integer> numFoo = new FooImpl<>(new Integer(42)); final Foo<String> strFoo = new FooImpl<>("asdf"); List<Foo<?>> foos = new ArrayList<>(3); foos.add(objFoo); foos.add(numFoo); foos.add(strFoo); resetFoos(foos); // compile error System.out.println("done"); } ``` The compile error reads: method `resetFoos` cannot be applied to given types; required: `Iterable<Foo<T>>` found: `List<Foo<?>>` reason: no instance(s) of type variable(s) `T` exist so that argument type `List<Foo<?>>` conforms to formal parameter type `Iterable<Foo<T>>` where `T` is a type-variable: `T extends Object` declared in method `<T>resetFoos(Iterable<Foo<T>>)` (using sun-jdk-1.7.0_10 via ideone.com)

Original source