Control Invocation Syntax++

Peter Levart peter.levart at marand.si
Tue Dec 22 07:54:57 PST 2009


Hello Neal,

I'm trying to understand the Control Invocation Syntax in CfJ 0.6b (or 0.7b) where you write (I'm using [] notation here for 0..1 occurences):


"A new invocation statement syntax is added to make closures convenient for control abstraction: 

    ControlInvocationStatement: 
        [for] Primary ( FormalParameters [: ExpressionList] ) Statement 
        [for] Primary ( [ExpressionList] ) Statement 

This syntax is a shorthand for the following statement: 

    Primary ( [ExpressionList,] # ( [FormalParameters] ) ( Statement (Void)null ) );

"

I assume you are refering to grammar rules specified in the content of JLS 3rd edition - not in chapter 18.1 where the whole grammar is specified on one page and has different production rules.

In the "presentation friendly" grammar the "Primary" means a primary expression. JLS (15.2) describes one possible primary expression called "MethodInvocation":

    MethodInvocation:
        MethodName ( [ArgumentList] )
        Primary [. NonWildTypeArguments] Identifier ( [ArgumentList] )
        super [. NonWildTypeArguments] Identifier ( [ArgumentList] )
        ClassName . super [. NonWildTypeArguments] Identifier ( [ArgumentList] )
        TypeName . NonWildTypeArguments Identifier ( [ArgumentList] )

In analogy with the above (by the way, I think there's an error in MethodInvocation's last production rule - "NonWildTypeArguments" should be optional there too) I assume your control invocation statement syntax was meant to be more or less like this:

    ControlInvocationStatement: 
        [for] MethodName ( FormalParameters [: ArgumentList] ) Statement
        [for] Primary [. NonWildTypeArguments] Identifier ( FormalParameters [: ArgumentList] ) Statement
        [for] super [. NonWildTypeArguments] Identifier ( FormalParameters [: ArgumentList] ) Statement
        [for] ClassName . super [. NonWildTypeArguments] Identifier ( FormalParameters [: ArgumentList] ) Statement
        [for] TypeName [. NonWildTypeArguments] Identifier ( FormalParameters [: ArgumentList] ) Statement
        [for] MethodName ( [ArgumentList] ) Statement
        [for] Primary [. NonWildTypeArguments] Identifier ( [ArgumentList] ) Statement
        [for] super [. NonWildTypeArguments] Identifier ( [ArgumentList] ) Statement
        [for] ClassName . super [. NonWildTypeArguments] Identifier ( [ArgumentList] ) Statement
        [for] TypeName [. NonWildTypeArguments] Identifier ( [ArgumentList] ) Statement

And that syntax being a shorthand for one of the following:

    MethodName ( [ArgumentList,] # ( [FormalParameters] ) ( Statement (Void)null ) );
    Primary [. NonWildTypeArguments] Identifier ( [ArgumentList,] # ( [FormalParameters] ) ( Statement (Void)null ) );
    super [. NonWildTypeArguments] Identifier ( [ArgumentList,] # ( [FormalParameters] ) ( Statement (Void)null ) );
    ClassName . super [. NonWildTypeArguments] ( [ArgumentList,] # ( [FormalParameters] ) ( Statement (Void)null ) );
    TypeName [. NonWildTypeArguments] Identifier ( [ArgumentList,] # ( [FormalParameters] ) ( Statement (Void)null ) );

I'm sure you meant that but it was to verbose to put into the spec. document.

...

Ok, now to something different. I was thinking about an alternative syntax. 

First, the syntax of parenthesized expression migh allow the expression in it to be optional:

    ParExpression:
        ( [BlockStatements] Expression ) 
        ( BlockStatements )

Meaning of Expressions: The specification for a parenthesized expression is modified to describe its new execution semantics: The block statements (if any) are executed in sequence, from left to right.  The result of the block expression is:

    * The type Nothing if there are block statements and the last block statement cannot complete normally; otherwise
    * The value and type of the final expression if there is one; otherwise
    * The type Void

Definite Assignment: The definite assignment rules for this construct are almost identical to that for the block statement.  The definite assignment state before the first block statement is the definite assignment state before the parenthesized expression. The definite assignment state before the subexpression (if there is one) is the definite assignment state following the last block statement. The definite assignment state after the parenthesized expression is the definite assignment state after the contained expression if there is one or the definite assignment state following the last block statement if there is no contained expression.


Next, instead of "ControlInvocationStatement" I would propose "ControlInvocation" expression (being one of possible "Primary" expressions):

    ControlInvocation: 
        [for] MethodName ( FormalParameters [: ArgumentList] ) ParExpression
        [for] Primary [. NonWildTypeArguments] Identifier ( FormalParameters [: ArgumentList] ) ParExpression
        [for] super [. NonWildTypeArguments] Identifier ( FormalParameters [: ArgumentList] ) ParExpression
        [for] ClassName . super [. NonWildTypeArguments] Identifier ( FormalParameters [: ArgumentList] ) ParExpression
        [for] TypeName [. NonWildTypeArguments] Identifier ( FormalParameters [: ArgumentList] ) ParExpression
        [for] MethodName ( [ArgumentList] ) ParExpression
        [for] Primary [. NonWildTypeArguments] Identifier ( [ArgumentList] ) ParExpression
        [for] super [. NonWildTypeArguments] Identifier ( [ArgumentList] ) ParExpression
        [for] ClassName . super [. NonWildTypeArguments] Identifier ( [ArgumentList] ) ParExpression
        [for] TypeName [. NonWildTypeArguments] Identifier ( [ArgumentList] ) ParExpression

Which would be a shortcut for one of the following:

    MethodName ( [ArgumentList,] # ( [FormalParameters] ) ParExpression )
    Primary [. NonWildTypeArguments] Identifier ( [ArgumentList,] # ( [FormalParameters] ) ParExpression )
    super [. NonWildTypeArguments] Identifier ( [ArgumentList,] # ( [FormalParameters] ) ParExpression )
    ClassName . super [. NonWildTypeArguments] ( [ArgumentList,] # ( [FormalParameters] ) ParExpression )
    TypeName [. NonWildTypeArguments] Identifier ( [ArgumentList,] # ( [FormalParameters] ) ParExpression )

Your "withLock" example:

    withLock(lock) {
        System.out.println("hello");
    }

Would then read like:

    withLock(lock) (
        System.out.println("hello");
    );

And would be a shorthand for:

    withLock(lock, #() (
        System.out.println("hello");
    ));

This would enable other possiblilities like this (using chained methods):

    List<String> someList = ...;

    String result =
        Parallel.list(someList)
                   .filter(String s)(!s.isEmpty())
                   .map(String s)(s.toLowerCase())
                   .reduce(String s1, String s2)(s1 + ":" + s2)
                   .execute(executor);

Or for example this (if the syntax is ever extended to support method names in pieces: http://gafter.blogspot.com/2007/01/methodnamesinpieces.html):

    StringBuilder sb = new StringBuilder("[");
    for each(String s : someCollection) (
        sb.append(s);
    ) inBetween (
        sb.append(", ");
    );
    sb.append("]");

...and this syntax would not be ambigous any more.

Maybe even Mark would be more satisfied with this syntax since it is using "(" and ")" which is consistent with syntax of "expression lambdas using paranthesized expression" that are transparent instead of "{" and "}" which might be associated with "statement lambdas" which are not transparent.


What do you think?

Peter



More information about the closures-dev mailing list