Updated ARM Spec

Joe Darcy joe.darcy at oracle.com
Thu Jul 15 14:44:34 PDT 2010


Greetings.

Starting with Project Coin proposal for Automatic Resource Management 
(ARM), in consultation with Josh Bloch, Maurizio, Jon, and others, Alex 
and I have produced a specification for ARM blocks that is much closer 
to Java Language Specification (JLS) style and rigor. The specification 
involves changes to the existing JLS section 14.20 "The try statement," 
and will eventually introduce a new subsection 14.20.3 "Execution of 
try-with-resources," although the specification below is not partitioned 
as such. Non-normative comments about the specification text below 
appear inside "[]". Differences between the new specification and the 
earlier Project Coin proposal for ARM are discussed after the specification.

-=-=-=-=-=-=-=-=-=-=-=-=-=-

SYNTAX: The existing set of grammar productions for TryStatement in JLS 
14.20 is augmented with:

TryStatement:
    try ResourceSpecification Block Catches_opt Finally_opt

Supporting new grammar productions are added:

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

[An implication of the combined grammar is that a try statement must 
have at least one of a catch clause, a finally block, and a resource 
specification. Furthermore, it is permissible for a try statement to 
have exactly one of these three components. Note that it is illegal to 
have a trailing semi-colon in the resource specification.]

A try-with-resources statement has a resource specification that 
expresses resources to be automatically closed at the end of the Block. 
A resource specification declares one or more local variables and/or has 
one or more expressions, each of whose type must be a subtype of 
AutoCloseable or a compile-time error occurs.

If a resource specification declares a variable, the variable must not 
have the same name as a variable declared earlier in the resource 
specification, a local variable, or parameter of the method or 
initializer block immediately enclosing the try statement, or a 
compile-time error occurs.

The scope of a variable declared in a resource specification of a 
try-with-resources statement (§14.20) is from the declaration rightward 
over the remainder of the resource specification and the entire Block 
associated with the try. Within the Block of the try, the name of the 
variable may not be redeclared as a local variable of the directly 
enclosing method or initializer block, nor may it be redeclared as an 
exception parameter of a catch clause in a try statement of the directly 
enclosing method or initializer block, nor may it be redeclared as a 
variable in the resource specification, or a compile-time error occurs. 
However, a variable declared in a resource specification may be shadowed 
(§6.3.1) anywhere inside a class declaration nested within the Block of 
the try.

The meaning of a try-with-resources statement with a Catches clause or 
Finally block is given by translation to a try-with-resources statement 
with no Catches clause or Finally block:

    try ResourceSpecification
      Block
    Catches_opt
    Finally_opt
    =>
    try {
      try ResourceSpecification
      Block
    }
    Catches_opt
    Finally_opt

In a try-with-resources statement that manages a single resource:

* If the initialization of the resource completes abruptly because of a 
throw of a value V, or if the Block of the try-with-resources statement 
completes abruptly because of a throw of a value V and the automatic 
closing of the resource completes normally, then the try-with-resources 
statement completes abruptly because of the throw of value V.

* If the Block of the try-with-resources statement completes abruptly 
because of a throw of a value V1, and the automatic closing of the 
resource completes abruptly because of a throw of a value V2, then the 
try-with-resources statement completes abruptly because of the throw of 
value V1, provided that V2 is an Exception. In this case, V2 is added to 
the suppressed exception list of V1. If V2 is an error (i.e. a Throwable 
that is not an Exception), then the try-with-resources statement 
completes abruptly because of the throw of value V2. In this case, V1 is 
not suppressed by V2.

If a try-with-resources statement that manages multiple resources:

*  If the initialization of a resource completes abruptly because of a 
throw of a value V, or if the Block of the try-with-resources statement 
completes abruptly because of a throw of a value V (which implies that 
the initialization of all resources completed normally) and the 
automatic closings of all resources completes normally, then the 
try-with-resources statement completes abruptly because of the throw of 
value V.

* If the Block of the try-with-resources statement completes abruptly 
because of a throw of a value V1, and the automatic closings of one or 
more resources (that were previously successfully initialized) complete 
abruptly because of throws of values V2...Vn, then the 
try-with-resources statement completes abruptly because of the throw of 
a value Vi (1 <= i <= n) determined by the translation below.

The exceptions that can be thrown by a try-with-resources statement are 
the exceptions that can thrown by the Block of the try-with-resources 
statement plus the union of the exceptions that can be thrown by the 
automatic closing of the resources themselves. Regardless of the number 
of resources managed by a try-with-resources statement, it is possible 
for a Catches_opt clause to catch an exception due to initialization or 
automatic closing of any resource.

A try-with-resources statement with a ResourceSpecification clause that 
declares multiple Resources is treated as if it were multiple 
try-with-resources statements, each of which has a ResourceSpecification 
clause that declares a single Resource. When a try-with-resources 
statement with n Resources (n > 1) is translated, the result is a 
try-with-resources statement with n-1 Resources. After n such 
translations, there are n nested try-catch-finally statements, and the 
overall translation is complete.

The meaning of a try-with-resources statement with a 
ResourceSpecification clause and no Catches clause or Finally block is 
given by translation to a local variable declaration and a 
try-catch-finally statement. During translation, if the 
ResourceSpecification clause declares one Resource, then the 
try-catch-finally statement is not a try-with-resources statement, and 
ResourceSpecification_tail is empty. If the ResourceSpecification clause 
declares n Resources, then the try-catch-finally statement is treated as 
if it were a try-with-resources-catch-finally statement, where 
ResourceSpecificationtail is a ResourceSpecification consisting of the 
2nd, 3rd, ..., nth Resources in order. The translation is as follows, 
where the identifiers #primaryException, #t, and #suppressedException 
are fresh:

    try ResourceSpecification
      Block
    =>
    {
    final VariableModifiers_minus_final R #resource = Expression;
    Throwable #primaryException = null;

    try ResourceSpecification_tail
      Block
    catch (final Throwable #t) {
      #primaryException = t;
      throw #t;
    } finally {
      if (#primaryException != null) {
        try {
          #resource.close();
        } catch(Exception #suppressedException) {
          #primaryException.addSuppressedException(#suppressedException);
        }
      } else {
        #resource.close();
      }
    }

If the Resource being translated declares a variable, then 
VariableModifiers_minus_final is the set of modifiers on the variable 
(except for final if present); R is the type of the variable 
declaration; and #resource is the name of the variable declared in the 
Resource.

Discussion: Resource declarations in a resource specification are 
implicitly final. For consistency with existing declarations that have 
implicit modifiers, it is legal (though discouraged) for a programmer to 
provide an explicit "final" modifier. By allowing non-final modifiers, 
annotations such as @SuppressWarnings will be preserved on the 
translated code. It is unlikely that the Java programming language will 
ever ascribe a meaning to an explicit final modifier in this location 
other than the traditional meaning. [Unlike the new meaning ascribed to 
a final exception parameter.]

Discussion: Unlike the fresh identifier in the translation of the 
enhanced-for statement, the #resource variable is in scope in the Block 
of a try-with-resources statement.

If the Resource being translated is an Expression, then the translation 
includes an local variable declaration for which 
VariableModifiers_minus_final is empty; the type R is the type of the 
Expression (under the condition that the Expression is assigned to a 
variable of type AutoCloseable); and #resource is a fresh identifier.

Discussion: The method Throwable.addSuppressedException has a parameter 
of type Throwable, but the translation is such that only an Exception 
from #resource.close() will be passed for suppression. In the judgment 
of the designers of the Java programming language, an Error due to 
automatic closing of a resource is sufficiently serious that it should 
not be automatically suppressed in favor of an exception from the Block 
or the initialization or automatic closing of lexically rightward 
resources.  [However, perhaps such an Error should instead be recorded 
as suppressing an exception from the Block or other lexically rightward 
component.]

Discussion: This translation exploits the improved precision of 
exception analysis now triggered by the rethrow of a final exception 
parameter.

The reachability and definite assignment rules for the try statement 
with a resource specification are implicitly specified by the 
translations above.

-=-=-=-=-=-=-=-=-=-=-=-=-=-

Compared to the earlier proposal, this draft specification:

* Assumes the revised supporting API with java.lang.AutoCloseable as the 
type indicating participation in the new language feature.

* Changes the official grammar for a declared resource from
      LocalVariableDeclaration
to
      VariableModifiers Type VariableDeclaratorId = Expression
The former syntactically allowed code like
      AutoCloseable a, b, c
which would not be useful in this context.

* Preserves modifiers on explicitly declared resources, which implies 
@SuppressWarnings on a resource should have the intended effect.

* States how the exception behavior of close methods is accounted for in 
determining the set of exceptions a try-with-resource statement can throw.

* Gives a more precise determination of the type used for the local 
variable holding a resource given as an Expression. This precision is 
important to allow accurate exception information to be computed.

* Provides typing constraints so that type inference works as expected 
if the Expression given as a Resource in a ResourceSpecification is, 
say, a generic method or null.

Compiler changes implementing this revised specification remain in 
progress. After experience is gained with the initial implementation, I 
expect various changes to the feature to be contemplated:

* Dropping support for a resource to be specified as a general 
Expression. Nontrivial specification and implementation complexities 
arise from allowing a general Expression to be used as resource. 
Allowing a restricted expression that was just a name may provide nearly 
all the additional flexibility at marginal additional implementation and 
specification impact.

* Adjustments to the suppressed exception logic: in the present 
specification, an incoming primary exception will suppress an Exception 
thrown by a close method; however, if the close method throws an error, 
that error is propagated out without suppressing an incoming primary 
exception. Possible alternatives include having a primary exception in a 
try-with-resource statement suppress all subsequent Throwables 
originating in the statement and having a non-Exception thrown by a 
close suppress any incoming primary exception.

These alternatives could be implemented by replacing the translated code

              try {
                #resource.close();
              } catch(Exception #suppressedException) {
                
#primaryException.addSuppressedException(#suppressedException);
              }

with

              try {
                #resource.close();
              } catch(Throwable #suppressedException) {
                
#primaryException.addSuppressedException(#suppressedException);
              }

or

              try {
                #resource.close();
              } catch(Exception #suppressedException) {
                
#primaryException.addSuppressedException(#suppressedException);
              } catch(Throwable #throwable) {
                #throwable.addSuppressedException(#primaryException);
                throw #throwable;
              }

respectively.

-Joe



More information about the coin-dev mailing list