3 ms·
I disagree. class Foo<T extends Number> implements IFoo<T> {} Does not implement an unconstrained T. It implements "T extends Number". When the T appears in a
by lowbloodsugar 10y ago
I disagree.
class Foo<T extends Number> implements IFoo<T> {}
Does not implement an unconstrained T. It implements "T extends Number". When the T appears in an implements, its not declaring a new type. You can't do, for example
class Foo implements IFoo<T> {}
java: cannot find symbol T
The mistake is believing that the T's, in the example above, are in any way related. It would be more appropriate to write:
interface Foo<TUnconstrained> {}
class Foo<TExtendsNumber extends Number> implements IFoo<TExtendsNumber> {...}
And then it becomes clear that the foos in bar will never be a Foo, because Foo does not implement IFoo<String> and never will. Yes you can nuke it unchecked code. No, I don't have a problem with that. But the example given is not a useful example.
And this example is in response to the previous one where he asks "Is this code safe? .. your gut instinct would say this is unsafe". No. My gut instinct is that it would not compile. And indeed:
java: type argument java.lang.String is not within bounds of type-variable T
- munificent 10y ago> I disagree. I don't know what you're disagreeing with. > And then it becomes clear that the foos in bar will never be a Foo, because Foo does not implement IFoo<String> and never will. The statement "Foo does not implement IFoo<String>" is not meaningful. "Foo" is not a type, it's a type constructor. To refer to a type, you need to say Foo of what. And it is the case that Foo<String> implements IFoo<String>. Consider: interface IFoo<TUnconstrained> { Number foo(TUnconstrained t); } void useFoo(IFoo<String> foo) { Number n = foo.foo("not a number"); } This code compiles fine. Add this: class Foo<TExtendsNumber extends Number> implements IFoo<TExtendsNumber> { public Number foo(TExtendsNumber t) { return t; } } It still compiles fine. This is exactly what the author is saying. The reason it is fine for the compiler to permit the above code is because it is relying on the fact that you will not be able to instantiate Foo<String>. This is one half of the puzzle of the actual unsoundness example. The other half is that you can then sidestep that restriction using a wildcard to define a type that hypothetically meets the required bound even though no such real type exists. That would still be safe, since you've never be able to initialize that variable since no value of that type is possible. Except that Java lets you initialize it with null.