lambda explicit type declaration.

Sergey Kuksenko sergey.kuksenko at oracle.com
Mon Nov 26 04:40:43 PST 2012


Hi,

I'd like to ask about lambda with explicit parameters type declaration. 
There is a difference between method reference and lambda. Method 
reference parameters should be assignable to types of functional 
interface method parameters, but lambda parameters should be the same as 
types of functional interface method parameters. Different rules leads 
to inconsistency between lambda & method references (it is my opinion - 
I understand that others may think such inconsistency is ok). I think 
such strict rule for lambda makes less value of the ability to declare 
lambda parameter types explicitly.

Let's consider a couple examples.

1. Well known "boxed value equals" problem.

Comparator<Integer> wrong_comparator
		= (x, y) -> (x < y) ? -1 : ((x == y) ? 0 : 1);

And I expecting more similar bugs in the new code with lambdas, 
especially in places where generic boxed and specialised primitive 
functional interfaces are used. Developers will misthink, misprint, 
misevaluate type inference ....

The best (IMO) way to fix the problem is not allowed right now:

Comparator<Integer> fixed_comparator
		= (int x, int y) -> (x < y) ? -1 : ((x == y) ? 0 : 1);
	// won't compile.

Other ways to fix it are not such simple like:

Comparator<Integer> fixed_comparator = (a,b) -> {
                        int x = a;
                        int y = b;
                        return (x < y) ? -1 : ((x == y) ? 0 : 1);
                      };


2. Fields access.

We have two classes:

     class A {
         public int foo  = 42;
     }

     class B extends A {
         public int foo = 43;
     }

and two mappers:

         Mapper<Integer, A> defoogaringA0 = a -> a.foo;
         Mapper<Integer, B> defoogaringB0 = a -> a.foo;

Results are different:
         System.out.println( defoogaringA0.map(new B())); // print 42
         System.out.println( defoogaringB0.map(new B())); // print 43

and it is the results should be. But we don't have a convenient way to 
manage it. Like lets create a method:

     static int defoo(A a) {
         return a.foo;
     }

and two mappers:

         Mapper<Integer, B> defoogaringB1 = Test::defoo;
         Mapper<Integer, A> defoogaringA1 = Test::defoo;

         System.out.println( defoogaringA1.map(new B())); // print 42
         System.out.println( defoogaringB1.map(new B())); // print 42

So if I have a stream of <B> elements - I can't process them with lambda 
accepting type A, because of even explicitly declared type should be the 
same as inferred - <B>. The only way is using method references or 
expressions like:

         Mapper<Integer, B> defoogaringB2 = (B a) -> ((A)a).foo;

         System.out.println( defoogaringB2.map(new B())); // print 42

But again I can't write a simple expression:

         Mapper<Integer, B> defoogaringB2 = (A a) -> a.foo; // won't compile






-- 
Best regards,
Sergey Kuksenko


More information about the lambda-dev mailing list