Project Coin: JSR 334 Expert Group Update

Besides working to address issues identified in the EDR draft, such as refining the diamond specification, the JSR 334 expert group has been considering other matters as well. One change being contemplated is removing the ability to have multiple underscores between digits of a literal; under that possible change, no underscore or a single underscore would be allowed. The primary consideration here is to prevent abuses of the underscores in literal feature that would obscure program meaning; on the other hand, there may be reasonable uses of repeated underscores that are desirable to allow.

The expert group has agreed to one significant change from the EDR draft: as called out as a possibility in the draft, support has been dropped for the general expression form of the try-with-resources statement. That is, support has been removed for passing a resource as a general expression without an accompanying explicit variable declaration.

Several technical problems were identified with allowing a general expression:

  • Syntactic ambiguity: In the parser, it was not always possible to distinguish with one-token look-ahead between the start of an Expression and the start of a Type. Consider code like

      try(i < j // Ternary operator on variables i and j
          ? new Resource1() :
            new Resource2()) {...}
    

    compared to code like

      try(Box < Resource // Simple generic wrapper around a resource
          > resourceBox = Box<>(new Resource1())) {...}
    

    A natural grammatical fallback short of banning Expression would be to only allow a more restricted expression, such as Identifier. However, that restricted grammar would require compiler changes to alert programmers to some surprising legal code, as given in the following examples.

  • Usability issues: Consider a try-with-resources statement being used to manage an existing variable where the variable is mutated inside the try block:

    public class TwrExamples implements AutoCloseable {
       public static void main(String... args) {
           TwrExamples twrEg1 = new TwrExamples();
           System.out.println(twrEg1.hashCode());
    
           try(twrEg1) {
               twrEg1 = new TwrExamples();  // Mutating the variable!
               System.out.println(twrEg1.hashCode());
           }
       }
    
       @Override
       public void close() {
           System.out.println(hashCode());
       }
    }
    

    As try-with-resources was previously specified, this would cause close to be called on the original value, not the value twrEg1 pointed to at the time the try block finishes. In this case, the printed output of the program may be something like:
    1607576787
    1051296202
    1607576787
    which indicates that while close was called on the original value, close was not called on the new TwrExamples object created inside the try-with-resources block. Either policy of calling code on the original value or the value on exit of the block could be problematic. The compiler did not issue any warnings about this situation and warnings should be added if this feature were to be kept. (Mutating a resource variable declared as part of the try-with-resources statement is illegal since such variables are implicitly or explicitly final).

Other complications that stemmed from supporting a general expression as a resource were making sure the specification and implementation accepted both

   try(null) {...}
and
   try(myGenericMethodThatInfersTheTypeOfItsResult()) {}
as valid programs.

The main rationale for supporting general expressions was to allow non-Closeable objects, such as locks, to be easily wrapped in a suitable type to enjoy the call-method-on-block-exit guarantees of try-with-resources. When this is desirable, the same effect can still be achieved with an explicit resource declaration. As experience is gained with try-with-resources, extensions to support other usage patterns will be considered in future releases.

I'm working with the javac team to remove support for this feature in an upcoming JDK 7 build.

Comments:

Why is it in the try-with-resource statement syntactic ambiguity causes a problem.

If these two expressions exist outside the try-with-resource statement the parser is able to function and the code will get parsed. When inside the statement the parser assumably requires some sort of awareness between whether it is the start of a Type or Expression but why?

Posted by whatsthebeef on January 24, 2011 at 01:00 AM PST #

@whatsthebeef,

In parsing, the compiler must decide, at some point, between which grammatical alternatives to use to construct the parse tree from the source. An unambiguous grammar is desired so that a program has a unique parse tree, and thereby a specific meaning and interpretation. In this case, while Expression and Type are usable elsewhere in the grammar and parsed successfully by the compiler, the text the two grammar fragments can generate overlap by more than one token of lookahead, meaning they cannot be distinguished just be looking one token ahead.

Posted by Joe Darcy on January 24, 2011 at 02:35 AM PST #

Thus, is the production:

TryStatement:
try ResourceSpecification Block Catchesopt Finallyopt

ResourceSpecification:
( Resources )
Resources:
Resource
Resource ; Resources
Resource:
VariableModifiers Type VariableDeclaratorId = Expression
Expression

I pulled from http://blogs.sun.com/darcy/entry/project_coin_updated_arm_spec the ambiguity would be introduced by the existance of the 'VariableModifiers Type VariableDeclaratorId' and 'Expression' beneath 'Resource' and the fact the compiler is unclear which to select, how might the new production look for Resource?

I am writing a blog post to help newcomers to understand some ofthe technical side of the JSR process and am wanting to be completely accurate.

Posted by whatsthebeef on January 25, 2011 at 02:30 AM PST #

@whatsthebeef,

To understand the problem, I suggest you research "first and follow sets" in the context of compilers or context free grammar parsing.

Note that there is a bug, which has been corrected in the early draft review of JSR 334, in the grammar above

VariableModifiers

should be

VariableModifiers_opt

that is, the variable modifiers, final or an annotation, are optional. (If the variable modifiers were required, this particular parsing bug would go away since the compiler could tell VariableDeclaratorId form vs. the Expression form by looking at the first token after the left parenthesis.)

Posted by Joe Darcy on January 25, 2011 at 02:46 AM PST #

@Joey Darcy

Thanks, I understand this particular technical problem now. Because of some mental block and the fact I should have read your example closer I had it stuck in my head that the resource passed was already defined and therefore (using the example you stated, which I should have read closer) the 'Box < Resource >' wasn't included and I couldn't see where the ambiguity came in.

I have been reading up on compilers and even played around a little with JavaCC and EBNF which uses different notation as I am sure you know.

I am using your blog posts on progress with the JDK7 to understand on a much lower level the Java language. Would appreciate if you could have a glance at my post when I publish and point out any inaccuracies as I am using this as a demonstration of some of the techniques, no probs if not though.

Posted by whatsthebeef on January 25, 2011 at 03:35 AM PST #

Would it be better to make the resource declaration implicitly final to prevent:

try(TwrExamples twrEg1 = new TwrExamples()) {
twrEg1 = new TwrExamples(); // Mutating the variable!
System.out.println(twrEg1.hashCode());
}

You could issue a warning, but it would almost certainly be a mistake. Therefore why not ban it.

-- Howard.

Posted by Howard Lovatt on February 26, 2011 at 06:38 AM PST #

@Howard,

An explicit try-with-resource resource variable has been implicitly final since before July 2010:
http://blogs.sun.com/darcy/entry/project_coin_updated_arm_spec

The try-with-resources implementation in JDK 7 has enforced the (at least) implicitly final property since it was available in promoted builds of JDK 7 starting last August:
http://blogs.sun.com/darcy/entry/project_coin_try_out_try

Posted by Joe Darcy on February 26, 2011 at 10:01 AM PST #

Hi Joe,

Sorry I hadn't kept up to date with the proposal, my apologies.

With regard to the variable use case:

try(twrEg1) {
twrEg1 = new TwrExamples(); // Error must be final!
System.out.println(twrEg1.hashCode());
}

You could use the lambda/inner class rule of final or effectively final and this would be consistent with the implicitly final rule for the declaration case, i.e. I don't think it would surprise anyone.

The expression use case is harder. In your example of:

try ( x < y ? r1 : r2 ) { ... }

or

try ( x < y > r = new x < > ( ) ) { ... }

In many cases, I would expect all real world cases, x won't exist as both a variable and as a type and therefore you can resolve which is which (C++ compilers do this for if statements where an expression or declaration can occur). If x is undefined at this point in parsing or does exist as both a variable and a type then you emit an error message. The programmer can resolve the issue either with a separate line of code or using brackets to indicate an expression. (It is a great pity Java has two name spaces!)

I am sure you would have considered this, so I am assuming that this approach is too complex inside the compiler, undesirable form a compiler speed point of view, difficult to produce a good error message for, or all of the above.

Sorry again for not realising the spec. had changed.

Keep up the good work,

-- Howard.

Posted by Howard Lovatt on February 27, 2011 at 05:04 PM PST #

Post a Comment:
Comments are closed for this entry.
About

darcy

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
News

No bookmarks in folder

Blogroll