Problem with method references
Peter Levart
peter.levart at marand.si
Thu Jan 13 23:53:10 PST 2011
On 01/04/11, Maurizio Cimadamore wrote:
> On 03/01/11 10:10, Tomasz Kowalczewski wrote:
> > package org.tkowalcz.lambda.extractor;
> >
> > public class LambdaInConstructorExample {
> >
> > public static void main( final String[] args ) {
> > // Compiles fine
> > Extractor x = LambdaInConstructorExample#getArgCount;
> > }
> >
> > public LambdaInConstructorExample() {
> > // Error
> > Extractor x = LambdaInConstructorExample#getArgCount;
> > }
> >
> > public int getArgCount() {
> > return 1;
> > }
> > }
> There is no bug here. The first method reference compiles because a
> non-static method is being referenced from a static context - in such
> cases, the following expansion is automagically applied by the compiler:
>
> If f is an instance method of Z whose signature is A,B->C, then #obj.f
> is of type A,B->C and #Z.f is of type Z,A,B->C.
>
> Which means that, in the first case, the compiler is looking for a
> signature of the kind (LambdaInConstructorExample)->int.
>
> Since the second method reference occurs in a non-static context, no
> automatic expansion is applied, which means the compiler will look for a
> signature of the kind ()->int.
>
> Now, depending on how you declare the target method in the SAM type
> Extractor, you will not be able to get both method references to
> compile, as the compiler will be looking for different signatures. I
> guess that, looking at your output, your SAM type declaration looks like
> the following:
>
> interface Extractor {
> int getX(LambdaInConstructorExample arg);
> }
>
> Maurizio
>
Hello Maurizio,
I see that referencing instance methods from static context is a desirable feature, but syntax-wise I aggree with Neal that the same expression should not change its meaning if moved from static to instance context or vice-versa (when both contexts are legal). So I propose that the syntax:
#methodName
be made illegal for referencing instance methods from static context.
for example (using infix '#' - equivalent is possible with prefix '#'):
class C {
public int m(String s) { ... }
public static int sm(String s) { ... }
C() {
StringToInt f1 = this#m;
StringToInt f2 = #m; // equivalent as above
CStringToInt f3 = C#m;
StringToInt f4 = C#sm;
StringToInt f5 = #sm; // equivalent as above
StringToInt f6 = this#sm; // equivalent as above (to be consistent with method invocation)
new Runnable() {
public void run() {
StringToInt f1 = C.this#m;
CStringToInt f2 = C#m;
}
}.run();
}
static {
C c = new C();
StringToInt f1 = c#m;
// #m - illegal
CStringToInt f2 = C#m;
StringToInt f3 = C#sm;
StringToInt f4 = #sm; // equivalent as above
StringToInt f5 = c#sm; // equivalent as above (to be consistent with method invocation)
}
interface StringToInt {
int apply(String s);
}
interface CStringToInt {
int apply(C c, String s);
}
}
Regards, Peter
More information about the lambda-dev
mailing list