Project Lambda: Java Language Specification draft
Peter Levart
peter.levart at gmail.com
Sun Jan 24 10:24:34 PST 2010
On Friday 22 January 2010 23:55:17 Alex Buckley wrote:
> [15.8 Primary Expressions]
>
> Expression:
> LambdaExpression
>
> LambdaExpression:
> '#' '(' FormalParameterList_opt ')' '(' Expression_opt ')'
> '#' '(' FormalParameterList_opt ')' Block
>
> #()()
This is useless. Statement lambda already provides for no-op void lambda.
> #()(5)
> #()(x.m())
> #()((foo++))
> #()("a"+"b")
As Neal already pointed out, parenthesis around expression could be dropped. Expression already
allows them if needed - if they're not needed, why should we be forced to write them? Expression
lambdas should be as concise as possible.
> #()( {1,2,3} ) // Proposed collection literal expression from Coin
Well, without parentheses the above example shows why the proposed collection literal expression
syntax is inappropriate. That syntax is reserved for statements - expressions should not mess
with it. Without mandatory parentheses, this is ambiguous:
#() {}
...is this an expression lambda returning empty collection or a statement lambda returning void?
I would use '[' and ']' for collection literals. I think Coin and Lambda groups should work
together and recognize the level of importance a particular feature has for the Java language.
In my opinion lambdas are far more important than collection literals, so the syntax of
collection literals should bend not the syntax of lambda expressions.
> [15.8.3 this]
>
> The keyword this may be used only in the body of an instance method,
> instance initializer or constructor, or in the initializer of an
> instance variable of a class, *or in a lambda expression*.
>
I share the opinion of others (-1). If the reasoning behind your proposed handling of 'this' was
to support easy migration from anonymous inner implementations of SAM classes to statement
lambda expressions then your specification is not correct:
> The type of this in a lambda expression is the function type of the
> lambda expression.
The type of 'this' should be the subtype of SAM type that lambda expression was converted to -
analogously to the type of 'this' in methods of anonymous inner instance creation expressions.
If we want to mirror features of anonymous inner classes (return, etc.) then we should be
consistent or drop that desire and just create something entirely different - transparent lambda,
for example?
As others pointed out, I too don't think lambda conversion should support conversion to SAM
classes. There are too many problems. In particular if this conversion could be carried out at
unexpected places (casting from function type to SAM class, assignment of variable of function
type to variable of conversion-compatible SAM type). It would be too bad if the implementation
details of those conversions were not specified but left to the discretion of the compiler.
Exceptions thrown in the no-arg constructor of a SAM class could be thrown at different
unexpected places, depending on what compiler was used to compile the code. For example:
public abstract class Sam {
public Sam { throw new RuntimeException(); }
public abstract void f();
}
public class Test {
public void test() {
Sam sam = #() { System.out.println("Not printed"); }
sam.f();
}
}
Question: Should RuntimeException be thrown from the Test.test() method or when the Test class
is initialized (remember that compiler should be free to optimize lambda creation and/or
conversion).
Another example:
Timer timer = ...;
#void() task = #() { ...; ((TimerTask)this).cancel(); };
timer.schedule(task, ...);
Question: is the instance of TimerTask that is canceled inside the lambda body the same instance
as the instance passed to Timer.schedule() method? If it is not, then lambda is not canceling
the correct TimerTask...
Besides that the number of APIs that use SAM classes for method arguments is practically zero
compared to the number of APIs that use SAM interfaces.
> [15.8.6 Lambda Expressions]
...
>
> If the body of a lambda expression is a block, then either all or none
> of the return statements in the block must have an Expression. If no
> return statement has an Expression, then the body of the lambda
> expression is void, i.e. has no type. If all return statements have an
> Expression, then the types of the Expressions must be
> assignment-compatible with each other, or a compile-time error
> occurs. The type of the body is lub(T1..Tn) where T1..Tn are the types
> of the Expressions after boxing conversion.
I think it would be far more useful and consistent if the return type of the lambda expression
for the case of value-returning statement lambdas was defined by the existing specification of a
conditional operator ? : [15.25] (applying it's type reduction rule recursively), so the return
type of this lambda:
#() { if (condition) return "1"; else return 2; }
would be the same as of this lambda:
#() ( condition ? "1" : 2 )
This also handles (among others) this perfectly valid situation:
#() { if (condition) return "a"; else return null; }
Where your specification would produce compile-time error since String is not assignable to null
(type).
...
> [15.8.7 Lambda instance invocation]
Dot '.' is better than exclamation mark '!'. Another alternative is '->' (C++). It's more
noticeable in the noise. As others pointed out, if the syntax is different it should look
different.
Regards, Peter
More information about the lambda-dev
mailing list