JEP proposal: Improved variance for generic classes and interfaces
elias vasylenko
eliasvasylenko at gmail.com
Tue Oct 28 00:19:00 UTC 2014
Ah, good point. Covariance is still easy to have without any such fuss, so
far as I can see, but having the one without the other is no good.
I still think this at least bears further consideration. There could still
be a solution in allowing contravariant overriding in this particular
instance, i.e. having the user only need to implement test(Number) and
having the bridge method just call that... since conceptually test(Integer)
*should* have effectively been a bridge method *itself* to test(Number)
anyway. If anything, it would be better this way regardless of the erasure
issue imo, since it's just more strongly enforcing contravariance
relationship encoded by the Predicate<? super T> syntax.
There are still problems, since of course suddenly allowing contravariant
overrides in one specific scenario creates situations which behave
inconsistently with people's current expectations e.g.:
class Foo implements Predicate<Integer> {
public boolean test(Integer value) {return false;}
}
class Bar extends Foo implements Predicate<Number> {
public boolean test(Number value) {return true;}
}
foo.test((Integer) i); // returns true instead of false when invoked on
an instance of Foo!
Now that we have default methods we couldn't even just limit the feature to
interfaces to avoid the problem.
The only remotely tenable solution would be to force users to explicitly
override test(Integer) with a method which does nothing but forward the
invocation to test(Number). This would solve the erasure/bridge ambiguity,
as well as the general ban on contravariant overrides, but still isn't
ideal just because it feels a bit clunky... Syntax to explicitly mark a
method as a 'forwarding' method without having to specify a body would
help, but that is clearly outside the scope of this proposal, and a no-go
unless it could be justified in and of itself as worth the added language
complexity...
Any thoughts? Have I talked myself out of this? Are there other problems
I've missed in rambling on which make this moot, or does that about cover
it?
Cheers,
Eli
On 27 October 2014 23:03, Remi Forax <forax at univ-mlv.fr> wrote:
>
> On 10/27/2014 11:52 PM, Dan Smith wrote:
>
>> On Oct 26, 2014, at 4:53 PM, elias vasylenko <eliasvasylenko at gmail.com>
>>> wrote:
>>>
>>> Just a quick question/suggestion: it seems like a handy side-effect of
>>> the proposed changes is the potential for relaxation of the limitation on
>>> reimplementation of interfaces with different generic parametrisations, and
>>> I'm wondering if you've considered this.
>>>
>>> For example, it should be possible to allow something like this:
>>>
>>> class Foo implements Predicate<Integer> {}
>>>
>>> class Bar extends Foo implements Predicate<Number> {}
>>>
>>> Since declaration-site variance guarantees compatibility of the
>>> overriding parametrisation. Of course we can't technically override
>>> test(Integer) with test(Number)... but from an outsiders perspective I
>>> don't see this as incompatible with current language design philosophy...
>>> At any rate, covariance should be more straightforward
>>>
>>> I'm sure this would have come up if it hasn't already, but I couldn't
>>> find any explicit mention of it.
>>>
>> That's a good idea, and not something we've looked into yet. Thanks for
>> the suggestion.
>>
>> —Dan
>>
>
> The problem here is not a typing problem but an erasure problem, both
> Predicate<Integer> and Predicate<Number> require to generate a bridge
> method but both test(Integer) and test(Number) have the same erasure
> test(Object). So it's not possible without full reification to implement
> that bridge.
>
> cheers,
> Rémi
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20141028/0e353057/attachment-0001.html>
More information about the compiler-dev
mailing list