question about potentially compatible expression
Rafkind, Jon
jon.rafkind at hp.com
Thu Oct 17 16:01:28 PDT 2013
Ok I guess the reasoning is that type checking on method arguments is performed at the call-site and there cannot be any unstantiated type variables at that point.
class x<M>{
void bar(M m){
}
}
Here, M is unresolved in bar, but the class can still be separately compiled. When x is instantiated with a real type, the body of x is not revisited to see if M is compatible. The type system ensures that x can only be compiled if the bounds of M were compatible with the body.
Whereas for a method the arguments of the call site are checked for compatibility with the types of the parameters.
public <R extends Z> void bar(R r){
}
bar(this::q); // ok. R inferred to be exactly Z
This can fail to compile if R is explicitly instantiated as something other than a functional interface.
interface ZZ extends Z{
public void a();
public void b();
}
this.<ZZ>bar(this::q);
q.java: error ZZ is not a functional interface
The same reasoning shows why the 'R' type variable cannot be used inside the method to declare a functional interface variable.
public <R extends Z> void bar(){
R r = this::q;
}
q.java: R is not a functional interface
I suppose these cases would be allowed if the bodies of classes and methods were retyped when all type variables are instantiated, but that is impossible in the face of separate compilation and .class files (where some information is lost).
On 10/17/2013 02:13 AM, Paul Sandoz wrote:
> Hi Jon,
>
> For "class y<P extends Z"> we don't know what the type of P is so an instance of P cannot be created by class y. Further more, even if we could, P might not be a functional interface, for example:
>
> static interface ZZ extends Z {
> public void q();
> public void qq();
> }
>
> static class YY extends y<ZZ> { // P == ZZ
> public void doit(){
> ZZ zz = this::q; // Does this compile?
> }
> }
>
> For "public <P extends Z> void boo(P t)" then the type of P can be known since it is localized just to the method call, and in your example P is inferred to be Z (it cannot be anything else).
>
> Perhaps a clearer error message would help.
>
> Paul.
>
> On Oct 17, 2013, at 12:42 AM, "Rafkind, Jon" <jon.rafkind at hp.com> wrote:
>
>> In section 15.12.2.1 in JSR 335 is the following text
>>
>> A lambda expression, a method reference, or a constructor reference is potentially compatible with a type variable if the type variable is a type parameter of the candidate method.
>>
>> Why is there a restriction that the type parameter must be on the candidate method? This rules out the possibility of using a type parameter on the enclosing class as in the following code:
>>
>> public class y<P extends Z>{
>> public void boo(P t){
>> }
>>
>> public void q(){
>> }
>>
>> public void doit(){
>> boo(this::q);
>> }
>> }
>>
>> interface Z{
>> public void q();
>> }
>>
>> I get this error:
>>
>> $ javac8 y.java
>> y.java:9: error: incompatible types: P is not a functional interface
>> boo(this::q);
>>
>> But attaching 'P' to method 'boo' directly works.
>>
>> public <P extends Z> void boo(P t){
>> }
>>
More information about the lambda-dev
mailing list