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