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