From Joe.Darcy at Sun.COM Fri Feb 27 15:15:49 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Fri, 27 Feb 2009 15:15:49 -0800 Subject: Welcome to coin-dev Message-ID: <49A87425.3010506@sun.com> Welcome to the Project Coin development list! Project Coin is an effort around small language changes for JDK 7. The first phrase of the project is a call for proposals period running until March 30, 2009. To send in your idea, fill out a proposal form: http://openjdk.java.net/projects/coin#proposal_form and send it to this list. The proposals should be in plain text or HTML and be able to be evaluated stand-alone. After the call for proposals is completed, a subset of proposals will be selected for inclusion in a JSR draft. -Joe Darcy From Joe.Darcy at Sun.COM Fri Feb 27 15:20:11 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Fri, 27 Feb 2009 15:20:11 -0800 Subject: Proposal: Strings in Switch Message-ID: <49A8752B.5050408@sun.com> To start the discussions, here is my proposal for allowing Strings in switch. -Joe PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0 AUTHOR(S): Joseph D. Darcy OVERVIEW Provide a two sentence or shorter description of these five aspects of the feature: FEATURE SUMMARY: Should be suitable as a summary in a language tutorial. Add the ability to switch on string values analogous to the existing ability to switch on values of the primitive types. MAJOR ADVANTAGE: What makes the proposal a favorable change? More regular coding patterns can be used for operations selected on the basis of a set of constant string values; the meaning of the new construct should be obvious to Java developers. MAJOR BENEFIT: Why is the platform better if the proposal is adopted? Potentially better performance for string-based dispatch code. MAJOR DISADVANTAGE: There is always a cost. Some increased implementation and testing complexity for the compiler. ALTERNATIVES: Can the benefits and advantages be had some way without a language change? No; chained if-then-else tests for string equality are potentially expensive and introducing an enum for its switchable constants, one per string value of interest, would add another type to a program without good cause. EXAMPLES Show us the code! SIMPLE EXAMPLE: Show the simplest possible program utilizing the new feature. String s = ... switch(s) { case "foo": processFoo(s); break; } ADVANCED EXAMPLE: Show advanced usage(s) of the feature. String s = ... switch(s) { case "quux": processQuux(s); // fall-through case "foo": case "bar": processFooOrBar(s); break; case "baz": processBaz(s); // fall-through default: processDefault(s); break; } DETAILS SPECIFICATION: Describe how the proposal affects the grammar, type system, and meaning of expressions and statements in the Java Programming Language as well as any other known impacts. The lexical grammar is unchanged. String is added to the set of types valid for a switch statement in JLSv3 section 14.11. Since Strings are already included in the definition of constant expressions, JLSv3 section 15.28, the SwitchLabel production does not need to be augmented. The existing restrictions in 14.11 on no duplicate labels, at most one default, no null labels, etc. all apply to Strings as well. The type system is unchanged. The definite assignment analysis of switch statement, JLSv3 section 16.2.9, is unchanged as well. COMPILATION: How would the feature be compiled to class files? One way to support this change would be to augment the JVM's lookupswitch instruction to operate on String values; however, that approach is not recommended or necessary. It would be possible to translate the switches to equivalent if-then-else code, but that would require unnecessary equality comparisons which are potentially expensive. Instead, a switch should occur on a predictable and fast integer (or long) function value computed from the string. The most natural choice for this function is String.hashCode, but other functions could also be used either alone or in conjunction with hashCode. (The specification of String.hashCode is assume to be stable at this point.) If all the string labels have different lengths, String.length() could be used instead of hashCode. Generally a String.equals() check will be needed to verify the candidate string's identity in addition to the evaluation of the screening function because multiple string inputs could evaluate to the same result. A single case label, a single case label with a default, and two case labels can be special-cased to just equality checks without function evaluations. If there are collisions in String.hashCode on the set of case labels in a switch block, a different function without collisions on that set of inputs should be used; for example ((long)s.hashCode<<32 ) + s.length()) is another candidate function. Here are desugarings to currently legal Java source for the two examples above where the default hash code do not collide: // Simple Example if (s.equals("foo")) { // cause NPE if s is null processFoo(s); } // Advanced example { // new scope for synthetic variables boolean $take_default = false; boolean $fallthrough = false; $default_label: { switch(s.hashCode()) { // cause NPE if s is null case 3482567: // "quux".hashCode() if (!s.equals("quux")) { $take_default = true; break $default_label; } processQuux(s); $fallthrough = true; case 101574: // "foo".hashCode() if (!$fallthrough && !s.equals("foo")) { $take_default = true; break $default_label; } $fallthrough = true; case 97299: // "bar".hashCode() if (!$fallthrough && !s.equals("bar")) { $take_default = true; break $default_label; } processFooOrBar(s); break; case 97307: // "baz".hashCode() if (!s.equals("baz")) { $take_default = true; break $default_label; } processBaz(s); $fallthrough = true; default: $take_default = true; break $default_label; } } if($take_default) processDefault(s); } In the advanced example, the boolean "fallthrough" variable is needed to track whether a fall-through has occurred so the string equality checks can be skipped. If there are no fall-throughs, this variable can be removed. Likewise, if there is no default label in the original code, the $take_default variable is not needed and a simple "break" can be used instead. In a translation directly to bytecode, the synthetic state variables can be replaced with goto's; expressing this in pseudo Java source with goto: // Advanced example in pseudo Java with goto switch(s.hashCode()) { // cause NPE if s is null case 3482567: // "quux".hashCode() if (!s.equals("quux")) goto $default_label; goto $fooOrBarCode_label; case 101574: // "foo".hashCode() if (!s.equals("foo")) goto $default_label; goto $fooOrBarCode_label; case 97299: // "bar".hashCode() if (!s.equals("bar")) goto $default_label; $fooOrBarCode_label: processFooOrBar(s); break; case 97307: // "baz".hashCode() if (!s.equals("baz")) goto $default_label; processBaz(s); default: $default_label: processDefault(s); break; } Related to compilation, a compiler's existing diagnostics around falling through switches, such as java's -Xlint:fallthrough option and @SuppressWarnings("fallthrough"), should work identically on switch statements based on Strings. TESTING: How can the feature be tested? Generating various simple and complex uses of the new structure and verifying the proper execution paths occur; combinations to test include switch statements with and without fall-throughs, with and without collisions in the hash codes, and with and without default labels. LIBRARY SUPPORT: Are any supporting libraries needed for the feature? No. REFLECTIVE APIS: Do any of the various and sundry reflection APIs need to be updated? This list of reflective APIs includes but is not limited to core reflection (java.lang.Class and java.lang.reflect.*), javax.lang.model.*, the doclet API, and JPDA. Only reflective APIs that model statements in the source language might be affected. None of core reflection, javax.lang.model.*, the doclet API, and JDPA model statements; therefore, they are unaffected. The tree API in javac, http://java.sun.com/javase/6/docs/jdk/api/javac/tree/index.html, does model statements, but the existing API for switch statements is general enough to model the revised language without any API changes. OTHER CHANGES: Do any other parts of the platform need be updated too? Possibilities include but are not limited to JNI, serialization, and output of the javadoc tool. No. MIGRATION: Sketch how a code base could be converted, manually or automatically, to use the new feature. Look for sequences of if ("constant string".equals(foo)) or if (foo.equals("constant string")) and replace accordingly. COMPATIBILITY BREAKING CHANGES: Are any previously valid programs now invalid? If so, list one. All existing programs remain valid. EXISTING PROGRAMS: How do source and class files of earlier platform versions interact with the feature? Can any new overloadings occur? Can any new overriding occur? The semantics of existing class files and legal source files and are unchanged by this feature. REFERENCES EXISTING BUGS: Please include a list of any existing Sun bug ids related to this proposal. 5012262 Using Strings and Objects in Switch case statements. http://bugs.sun.com/view_bug.do?bug_id=5012262 URL FOR PROTOTYPE (optional): No prototype at this time. From neal at gafter.com Fri Feb 27 21:21:31 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 21:21:31 -0800 Subject: Proposal: Block Expressions for Java Message-ID: <15e8b9d20902272121q2f625b1cq3230f5260bcddfe4@mail.gmail.com> Block Expressions for Java*AUTHOR(S):*Neal Gafter *OVERVIEW*FEATURE SUMMARY:A parenthesized expression can now contain additional statements, for example declarations of temporary local variables to avoid recomputing a value used only within the expression. This feature is especially useful in machine-generated code. MAJOR ADVANTAGE:Allows the declaration of local temporary variables closer to the point of use. Simplifies programs that generate Java code, as temporary variables that are used in only a single expression can be declared with the expression. MAJOR BENEFIT:Simplifies some patterns of code (see above). Makes it easier to write expression-oriented code even though many APIs are statement- or side-effect-oriented. Allows temporaries to be declared closer to the point of use. MAJOR DISADVANTAGE:Slightly more complex language specification. Like most other language features, can be overused to the detriment of the readability of the code. ALTERNATIVES:In many cases, there are alternate though awkward ways of writing the code, such as introducing small helper functions that are used only once or introducing temporary variables. EXAMPLES SIMPLE EXAMPLE:*double pi2 = (double pi = Math.PI ; pi*pi)**; // pi squared* ADVANCED EXAMPLE:*public static final Map primes = ( Map t = new HashMap(); t.put(1, 2); t.put(2, 3); t.put(3, 5); t.put(4, 7); Collections.UnmodifiableMap(t));* DETAILS SPECIFICATION:*Grammar*: the grammar for a parenthesized expression [JLS 15.8.5] is changed to: *ParExpression: **(** **BlockStatementsopt **Expression **)** * Note that the existing syntax for a parenthesized expression is a special case of this. *Meaning of Expressions*: The specification for a parenthesized expression should be modified to describe its new execution semantics: The block statements (if any) are executed in sequence, from left to right, exactly as in a block statement. The result of the parenthesized expression is the result of evaluating its subexpression. *Definite Assignment*: The definite assignment rules for this construct are almost identical to that for the block statement. The definite assignment state before the subexpression is the definite assignment state following the last block statement. *Exception Checking*: A parenthesized expression can throw exception type E if any statement or expression immediately contained in it can throw E. *Scoping*: Local variables and classes declared by an immediately contained statement is in scope until the end of the parenthesized expression. *Meaning of Statements*: No changes. *Type System*: No changes. COMPILATION:Compilation is straightforward, with one minor exception (no pun intended). The compiler must arrange the generated code such that the stack is empty at the beginning of any try statement that can complete normally when the try statement is embedded within a parenthesized expression. That is because the VM empties the stack when exceptions are handled. This can be accommodated by spilling values from the stack into VM locals. TESTING:Since the language change is completely local, it can be tested by exercising each of its interactions described above. LIBRARY SUPPORT:None required. REFLECTIVE APIS:No changes required. OTHER CHANGES:It would be desirable, at the same time that this change is made, to update the non-public Tree API that can be used with APT to express the syntax extension. MIGRATION:None required. COMPATIBILITY BREAKING CHANGES:No breaking changes. EXISTING PROGRAMS:No effect on existing programs. This is a pure extension. REFERENCES EXISTING BUGS:None. URL FOR PROTOTYPE (optional):None. From neal at gafter.com Fri Feb 27 21:22:44 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 21:22:44 -0800 Subject: Proposal: Improved Exception Handling for Java Message-ID: <15e8b9d20902272122p6a21f193g35c2df0000996018@mail.gmail.com> Improved Exception Handling for Java*AUTHOR(S):*Neal M Gafter *OVERVIEW* FEATURE SUMMARY: - Catching multiple exception types: A single catch clause can now catch more than one exception types, enabling a series of otherwise identical catch clauses to be written as a single catch clause. - Improved checking for rethrown exceptions: Previously, rethrowing an exception was treated as throwing the type of the catch parameter. Now, when a catch parameter is declared final, rethrowing the exception is known statically to throw only those checked exception types that were thrown in the try block, are a subtype of the catch parameter type, and not caught in preceding catch clauses. MAJOR ADVANTAGE: - Catching multiple exception types: Simplifies a commonly appearing pattern of redundant code. - Improved checking for rethrown exceptions: This improvement makes it possible to add a try-catch statement around a block of code to intercept, process, and rethrow an exception without affecting the statically determined set of exceptions thrown from the code. MAJOR BENEFIT:Greatly simplifies writing and maintaining code where intercepting or processing exceptions is common. MAJOR DISADVANTAGE:One-time implementation cost for adding the features to the compiler. Longer language specification in describing the behavior. ALTERNATIVES: - These behaviors are approximated currently by writing a series of identical catch clauses. During maintenance, the set of catch clauses must be modified so that it continues to match the set of exceptions statically thrown in the try block. With the proposed changes, the catch block can be written to catch a supertype of the set of exceptions to be intercepted, resulting in fewer catch clauses and fewer changes required when the try block evolves. EXAMPLES SIMPLE EXAMPLE:try { doWork(file); } catch (final IOException|SQLException ex) { logger.log(ex); * throw ex;* } ADVANCED EXAMPLE:*Show advanced usage(s) of the feature.* DETAILS SPECIFICATION: The grammar of Java is extended to allow a series of exception types, separated by the "OR" operator symbol, to be used in a catch clause: *CatchClause:* catch ( *CatchFormalParameter* ) *Block **CatchFormalParameter: VariableModifiers CatchType VariableDeclaratorId CatchType: DisjunctionType DisjunctionType: Type Type | DisjunctionType** * The type system is affected as follows: For the purpose of type checking, a catch parameter declared with a disjunction has type lub(t1, t2, ...) [JLS3 15.12.2.5]. For the purpose of exception checking [JLS3 11.2], a throw statement [JLS3 11.2.2] that rethrows a final catch parameter is treated as throwing precisely those exception types that - the try block can throw, - no previous catch clause handles, and - is a subtye of one of the types in the declaration of the catch parameter To avoid the need to add support for general disjunctive types, but leaving open the possibility of a future extension along these lines, a catch parameter whose type has more than one disjunct is required to be declared * final*. COMPILATION:A catch clause is currently compiled (before this change) to an entry in an exception table that specifies the type of the exception and the address of the code for the catch body. To generate code for this new construct, the compiler would generate an entry in the exception table for each type in the exception parameter's list of types. TESTING:The feature can be tested by compiling and running programs that exercise the feature. LIBRARY SUPPORT:No. REFLECTIVE APIS:No reflective API changes are required. OTHER CHANGES:It would be desireable, at the same time that this change is made, to update the non-public Tree API that can be used with APT to express the syntax extension. MIGRATION:None required. However, it would be easy to detect a series of otherwise identical catch clauses for different types and collapse them to a single catch clause. COMPATIBILITY BREAKING CHANGES:Joe Darcy observes that the following program compiles before this change, but not after: *try {* * throw new DaughterOfFoo();* * } catch (final Foo exception) {* * try {* * throw exception; // used to throw Foo, now throws DaughterOfFoo* * } **catch (SonOfFoo anotherException) { // Reachable?* * }* * }* However - This breakage is compile-time-only; already-compiled programs continue to behave as before - This kind of breakage is very unlikely to occur in practice, and - The broken code was likely wrong before, as it attempts to catch exceptions that simply cannot occur. EXISTING PROGRAMS:Except as above, none. REFERENCES EXISTING BUGS:No existing bugs that I am aware of. URL FOR PROTOTYPE (optional):An implementation of disjunctive catch parameters, but without special handling for final catch parameters: - http://www.javac.info/ See also - *Catching Multiple Exception Types:* http://www.javac.info/Multicatch.html - *Improved Checking for Rethrown Exceptions:* http://www.javac.info/Rethrown.html From neal at gafter.com Fri Feb 27 21:28:25 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 21:28:25 -0800 Subject: FYI: Proposal form in Google Docs... Message-ID: <15e8b9d20902272128w7cded30bkafec1d22737eee24@mail.gmail.com> I've just sent two proposals in rich-text email, but I see in the archives that they just show as a mess.? I'll resend as plain text. Regards, Neal From neal at gafter.com Fri Feb 27 21:30:24 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 21:30:24 -0800 Subject: Proposal: Block Expressions for Java In-Reply-To: <15e8b9d20902272121q2f625b1cq3230f5260bcddfe4@mail.gmail.com> References: <15e8b9d20902272121q2f625b1cq3230f5260bcddfe4@mail.gmail.com> Message-ID: <15e8b9d20902272130i3e52b349ta500f4b98accec01@mail.gmail.com> [Resending in plain text] Block Expressions for Java AUTHOR(S): Neal Gafter OVERVIEW FEATURE SUMMARY: A parenthesized expression can now contain additional statements, for example declarations of temporary local variables to avoid recomputing a value used only within the expression.? This feature is especially useful in machine-generated code. MAJOR ADVANTAGE: Allows the declaration of local temporary variables closer to the point of use.? Simplifies programs that generate Java code, as temporary variables that are used in only a single expression can be declared with the expression. MAJOR BENEFIT: Simplifies some patterns of code (see above).? Makes it easier to write expression-oriented code even though many APIs are statement- or side-effect-oriented.? Allows temporaries to be declared closer to the point of use. MAJOR DISADVANTAGE: Slightly more complex language specification.? Like most other language features, can be overused to the detriment of the readability of the code. ALTERNATIVES: In many cases, there are alternate though awkward ways of writing the code, such as introducing small helper functions that are used only once or introducing temporary variables. EXAMPLES SIMPLE EXAMPLE: double pi2 = (double pi = Math.PI ; pi*pi); // pi squared ADVANCED EXAMPLE: public static final Map primes = ( ??? Map t = new HashMap(); ??? t.put(1, 2); t.put(2, 3); t.put(3, 5); t.put(4, 7); ??? Collections.UnmodifiableMap(t)); DETAILS SPECIFICATION: Grammar: the grammar for a parenthesized expression [JLS 15.8.5] is changed to: ParExpression: ( BlockStatementsopt Expression ) Note that the existing syntax for a parenthesized expression is a special case of this. Meaning of Expressions: The specification for a parenthesized expression should be modified to describe its new execution semantics: The block statements (if any) are executed in sequence, from left to right, exactly as in a block statement.? The result of the parenthesized expression is the result of evaluating its subexpression. Definite Assignment: The definite assignment rules for this construct are almost identical to that for the block statement.? The definite assignment state before the subexpression is the definite assignment state following the last block statement. Exception Checking: A parenthesized expression can throw exception type E if any statement or expression immediately contained in it can throw E. Scoping: Local variables and classes declared by an immediately contained statement is in scope until the end of the parenthesized expression. Meaning of Statements: No changes. Type System: No changes. COMPILATION: Compilation is straightforward, with one minor exception (no pun intended).? The compiler must arrange the generated code such that the stack is empty at the beginning of any try statement that can complete normally when the try statement is embedded within a parenthesized expression.? That is because the VM empties the stack when exceptions are handled.? This can be accommodated by spilling values from the stack into VM locals. TESTING: Since the language change is completely local, it can be tested by exercising each of its interactions described above. LIBRARY SUPPORT: None required. REFLECTIVE APIS: No changes required. OTHER CHANGES: It would be desirable, at the same time that this change is made, to update the non-public Tree API that can be used with APT to express the syntax extension. MIGRATION: None required. COMPATIBILITY BREAKING CHANGES: No breaking changes. EXISTING PROGRAMS: No effect on existing programs.? This is a pure extension. REFERENCES EXISTING BUGS: None. URL FOR PROTOTYPE (optional): None. From neal at gafter.com Fri Feb 27 21:32:14 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 21:32:14 -0800 Subject: Proposal: Improved Exception Handling for Java In-Reply-To: <15e8b9d20902272122p6a21f193g35c2df0000996018@mail.gmail.com> References: <15e8b9d20902272122p6a21f193g35c2df0000996018@mail.gmail.com> Message-ID: <15e8b9d20902272132t214c30f3v23d0abf17b2f8c04@mail.gmail.com> [Resending in plain text] Improved Exception Handling for Java AUTHOR(S): Neal M Gafter OVERVIEW FEATURE SUMMARY: Catching multiple exception types: A single catch clause can now catch more than one exception types, enabling a series of otherwise identical catch clauses to be written as a single catch clause. Improved checking for rethrown exceptions:? Previously, rethrowing an exception was treated as throwing the type of the catch parameter. Now, when a catch parameter is declared final, rethrowing the exception is known statically to throw only those checked exception types that were thrown in the try block, are a subtype of the catch parameter type, and not caught in preceding catch clauses. MAJOR ADVANTAGE: Catching multiple exception types: Simplifies a commonly appearing pattern of redundant code. Improved checking for rethrown exceptions: This improvement makes it possible to add a try-catch statement around a block of code to intercept, process, and rethrow an exception without affecting the statically determined set of exceptions thrown from the code. MAJOR BENEFIT: Greatly simplifies writing and maintaining code where intercepting or processing exceptions is common. MAJOR DISADVANTAGE: One-time implementation cost for adding the features to the compiler. Longer language specification in describing the behavior. ALTERNATIVES: These behaviors are approximated currently by writing a series of identical catch clauses.? During maintenance, the set of catch clauses must be modified so that it continues to match the set of exceptions statically thrown in the try block.? With the proposed changes, the catch block can be written to catch a supertype of the set of exceptions to be intercepted, resulting in fewer catch clauses and fewer changes required when the try block evolves. EXAMPLES SIMPLE EXAMPLE: try { ??? doWork(file); } catch (final IOException|SQLException ex) { ??? logger.log(ex); ??? throw ex; } ADVANCED EXAMPLE: Show advanced usage(s) of the feature. DETAILS SPECIFICATION: The grammar of Java is extended to allow a series of exception types, separated by the "OR" operator symbol, to be used in a catch clause: CatchClause: catch ( CatchFormalParameter ) Block CatchFormalParameter: VariableModifiers CatchType VariableDeclaratorId CatchType: DisjunctionType DisjunctionType: Type Type | DisjunctionType The type system is affected as follows: For the purpose of type checking, a catch parameter declared with a disjunction has type lub(t1, t2, ...) [JLS3 15.12.2.5].? For the purpose of exception checking [JLS3 11.2], a throw statement [JLS3 11.2.2] that rethrows a final catch parameter is treated as throwing precisely those exception types that the try block can throw, no previous catch clause handles, and is a subtye of one of the types in the declaration of the catch parameter To avoid the need to add support for general disjunctive types, but leaving open the possibility of a future extension along these lines, a catch parameter whose type has more than one disjunct is required to be declared final. COMPILATION: A catch clause is currently compiled (before this change) to an entry in an exception table that specifies the type of the exception and the address of the code for the catch body. To generate code for this new construct, the compiler would generate an entry in the exception table for each type in the exception parameter's list of types. TESTING: The feature can be tested by compiling and running programs that exercise the feature. LIBRARY SUPPORT: No. REFLECTIVE APIS: No reflective API changes are required. OTHER CHANGES: It would be desirable, at the same time that this change is made, to update the non-public Tree API that can be used with APT to express the syntax extension. MIGRATION: None required.? However, it would be easy to detect a series of otherwise identical catch clauses for different types and collapse them to a single catch clause. COMPATIBILITY BREAKING CHANGES: Joe Darcy observes that the following program compiles before this change, but not after: try { ? throw new DaughterOfFoo(); } catch (final Foo exception) { ? try { ? ? ?throw exception; // used to throw Foo, now throws DaughterOfFoo ? } catch (SonOfFoo anotherException) { // Reachable? ? } } However This breakage is compile-time-only; already-compiled programs continue to behave as before This kind of breakage is very unlikely to occur in practice, and The broken code was likely wrong before, as it attempts to catch exceptions that simply cannot occur. EXISTING PROGRAMS: Except as above, none. REFERENCES EXISTING BUGS: No existing bugs that I am aware of. URL FOR PROTOTYPE (optional): An implementation of disjunctive catch parameters, but without special handling for final catch parameters: http://www.javac.info/ See also Catching Multiple Exception Types: http://www.javac.info/Multicatch.html Improved Checking for Rethrown Exceptions: http://www.javac.info/Rethrown.html From jjb at google.com Fri Feb 27 21:28:29 2009 From: jjb at google.com (Joshua Bloch) Date: Fri, 27 Feb 2009 21:28:29 -0800 Subject: Proposal: Automatic Resource Management Message-ID: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> (See att.) From neal at gafter.com Fri Feb 27 21:43:42 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 21:43:42 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> Message-ID: <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> Attachments not supported. Include your proposal inline. From jeremy.manson at gmail.com Fri Feb 27 22:10:25 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Fri, 27 Feb 2009 22:10:25 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation Message-ID: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> Improved Type Inference for Generic Instance Creation (Sorry about the length; I probably got a little carried away) Author: Jeremy Manson Overview Feature Summary This proposal addresses the addition of limited type inference for class instance creation expressions to the Java programming language. In cases where parametrized types need to be explicitly declared for a constructor, and the full parametrized type < T1 , T2 , ...Tn > of that constructor is obvious from the context, then the parameterized type of the constructor can be replaced with an empty set of type parameters: <>. The <> construct is legal to use when constructing an ob ject and either assigning it to a variable, or when passing it as a parameter. For example, consider the following assignment statement: Map> anagrams = new HashMap>(); This is rather lengthy, so it can be replaced with this: Map> anagrams = new HashMap<>(); Major Advantages Generics have had a tremendously positive impact on type safety in the Java programming language. They have made it possible to provide static guarantees about the type of instances used by other classes, preventing entire classes of runtime errors from occurring. However, generics have added complexity to Java, making the code far more verbose and occasionally di?cult to read. Although solving this problem is well outside the scope of this proposal, a limited form of type inference would remove unnecessary redundancy from the language. The requirement that type parameters be duplicated unnecessarily like this encourages an unfortunate overabundance of static factory methods, simply because type inference works on method invocations. For example, the Google collections library [2] contains a class that wraps every possible constructor of every subclass of java.util.List in the JDK: public class Lists { public static List newArrayList() { return new ArrayList(); } public static List newArrayList(int i) { return new ArrayList(i); } // ... } List list = Lists.newArrayList(); This approach avoids the redundancy in the declaration, but requires two declarations for every possible constructor in every possible class. This is ugly: every time a constructor or a new subtype of List is created, this class must be updated. Furthermore, the names of these methods does not have to be consistent; there is no reason to favor newArrayList over createArrayList. The proposed feature would make this approach obsolete. Major Disadvantages As a minor change, the impact of this feature would have few disadvantages. It does have bene?ts and drawbacks when compared with other implementations, though. For example, it could be argued that inference would look cleaner without the <> token: Map> list = new Map(); Unfortunately, for the purposes of backwards compatibility, new Map() indicates a raw type, and therefore cannot be used for type inference. An argument can also be made for more full type inference: auto map = new HashMap(); map.get("Foo"); // map is understood to be a Map or, alternatively, for a typedef like feature, where type identi?ers are assigned to longer typenames: typedef MyMap HashMap>; MyMap m = new MyMap(); Both of these approaches, which are present in the forthcoming C++ standard, would eliminate a lot of verbosity, at the expense of (potentially) obscuring the type of the variable. Neither of these proposals are precluded by this proposal; one, both or neither can be done at a later date. 2 Examples Here is a simple example, showing a use case for type inference for blank ?nals. An ImmutableMap is a Map implementation that throws an exception when mutation is attempted. In this example, the programmer writes > twice instead of four times, and once instead of twice: class AllAnagrams { final Map> anagrams; AllAnagrams(List originals) { Map> map = new HashMap<>(); // saves typing for (String s : originals) { String alphagram = alphagram(word); List group = anagrams.get(alphagram); if (group == null) anagrams.put(alphagram, group = new ArrayList<>()); // saves typing group.add(word); } anagrams = new ImmutableMap<>(map); // saves typing } private static String alphagram(String s) { char[] chars = s.toCharArray(); Arrays.sort(chars); return String.valueOf(chars); } } Here is another example, showing a use case for type inference in parameter passing: class TreeNode { T value; TreeNode left, right; private List> buildPathsInternal( List> list, List currPath, TreeNode node) { if (node == null) { // type inference does not save typing here; see section on Wildcards. list.add(new ArrayList(currPath)); return list; } currPath.add(node); buildPathsInternal(list, currPath, node.left); buildPathsInternal(list, currPath, node.right); currPath.remove(node); return list; } public List> getAllPaths(TreeNode head) { // Type inference saves typing here: return buildPathsInternal(new ArrayList<>(), new LinkedList<>(), head); } } Details Speci?cation Informally, the speci?cation adds syntax to replace the type arguments < T1 ...Tn > to a class being instanti- ated by a call to new with the simple token <>. It also provides a new conversion that infers what the type arguments would have been from the context, and treats the instance creation as if those type arguments were present. Syntax The syntax of the new statement is currently given in two di?erent ways in the Java Language Speci?cation (JLS) [1] ?15.9 and JLS?18.1 For simplicity, we restrict ourselves to the grammar given in ?15.9. ClassInstanceCreationExpression ::= new TypeArguments_opt ClassOrInterfaceCreationType ( ArgumentList_opt ) ClassBody_opt Primary . new TypeArguments_opt Identifier PossiblyInferredTypeArguments ( ArgumentList_opt ) ClassBodyopt ClassOrInterfaceCreationType ::= TypeDeclSpecifier PossiblyInferredTypeArguments_opt PossiblyInferredTypeArguments ::= <> TypeArguments_opt Semantics and Compilation Consider G1 , a generic type that is declared with 0 type arguments, and G2 ?T1 , T2 , ..., Tn ?, a generic type that is declared with n type arguments. There is a Type Inference Conversion from G1 to G2 if and only if ? G2 ?s erased type is a supertype of G1 ?s erased type and ? all type arguments T1 , T2 ...Tn uniquely identify reference types (i.e., they have no wildcard type arguments, although see below for more discussion of this). A Type Inference Conversion can take place in an assignment or method invocation conversion context (JLS ?5). It might be possible to allow the inference to take place in a casting conversion context; see Section 6.1 for more discussion of this. Type Inference Conversions are unique in that they are not actually performed. Instead, they are used to replace the type they would ordinarily be converting: if a Type Inference Conversion can take place, then the type parameters of G1 in the conversion context are deemed to be identical to those of type G2 . Compilation The resulting bytecode would be identical to bytecode generated by the same code with the types inferred. Testing The proposed construct can be tested by writing a number of statements that construct instances using inferred types. These instances can then be assigned to variables and ?elds of speci?c types, and passed to methods that expect speci?c types. These tests should compile and run as expected: Set set = new SortedSet<>(); set.add("A"); set.add("B"); set.add("C"); // verify that set contains "A", "B", "C". Other tests can be performed by attempted to place new instances of inferred types in contexts that contain wildcards; these tests should fail: List list = new ArrayList<>(); // should fail List list = new ArrayList<>(); list.add("A"); list.addAll(new ArrayList<>()); // should fail, since addAll expects // Collection Library Support No library support is required, although libraries can be rewritten to take advantage of the new feature. Re?ective APIs No re?ective APIs need to be changed. The only related API is Class.newInstance; however, because generics are not rei?ed in Java, this API does not take type parameters. A compiler cannot infer non- existent type parameters. Other Changes No other parts of the platform need to be updated. Migration Libraries can be rewritten to take advantage of this feature, but it is not imperative that they do so. Compatibility This change is backwards compatible. It will not make any changes to break existing compilation strategies or existing code. References Existing Bugs: 4879776, 6242254, 5092426, 6220689, 4983159, 6368076 [1] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java Language Speci?cation, 3rd Edition. Addison Wesley, 2004. [2] Google Inc. Google Collections Classes. Additional Features Casting Conversion It would be possible to specify Type Inference Conversion so that it takes place in a Cast Context: List emptyList() { return (List) new ArrayList<>(); } This would keep the casting context consistent with the other conversion contexts. However, the utility of this is questionable, so an argument could be made that this is a needless change. Wildcards In the method buildPathsInternal in Section 2, we need to use ArrayList?s copy constructor to create a copy of a List, but cannot: if (node == null) { list.add(new ArrayList(currPath)); return list; } The inference does not work here because the ArrayList constructor expects an argument of type Collection. The approach to inference described above needs to be able to determine the exact type of the type parameters being inferred. Since we don?t have an exact type here, the inference will fail. One possible tweak to our approach would be the ability to infer an actual type parameter from a wildcard. For example, if the least upper bound of a wildcard expression, when evaluated, would be a legal type parameter for the type being instantiated, we might consider inferring that type. This would make it possible to use type inference in the example above: if (node == null) { // > is inferred from Collection list.add(new ArrayList<>(currPath)); return list; } Further inference for method parameters As pointed out above, the result of a generic method: public static List newArrayList() { return new ArrayList(); } can be used for assignment: List list = Lists.newArrayList(); Although this construct can be used for assignment, it cannot be used in parameter passing when a type argument is required: public void expectStringList(List list) { ... } expectStringList(Lists.newArrayList()); // doesn?t compile expectStringList(Lists.newArrayList()); // does compile The fact that inference works for assignment but not for parameter passing is very confusing and arbitrary. Changing this would be consistent with the way type inference is presented in this proposal. From neal at gafter.com Fri Feb 27 22:28:36 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 22:28:36 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> Message-ID: <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> Jeremy- Where your spec says "the type parameters of G1 in the conversion context are deemed to be identical to those of type G2" seems to assume that the types G1 and G2 are related in a way that their type parameters align exactly. That is not the case in general. G1 and G2 might have different numbers of type parameters or they might have "corresponding" parameters in a different order. The most significant problem with this proposal is that it completely ignores the most difficult aspect of this feature - the required modifications to the type inference algorithm specified in the JLS (15.12.2.7 and 15.12.2.8). Joe Darcy and I discussed how to specify that on Friday, and I believe he is preparing a proposal. Regards, Neal On Fri, Feb 27, 2009 at 10:10 PM, Jeremy Manson wrote: > Improved Type Inference for Generic Instance Creation > > (Sorry about the length; I probably got a little carried away) > > Author: Jeremy Manson > > Overview > > Feature Summary > > This proposal addresses the addition of limited type inference for > class instance creation expressions to the Java programming language. > In cases where parametrized types need to be explicitly declared for a > constructor, and the full parametrized type < T1 , T2 , ...Tn > of > that constructor is obvious from the context, then the ?parameterized > type of the constructor can be replaced with an empty set of type > parameters: <>. The <> ?construct is legal to use when constructing an > ob ject and either assigning it to a variable, or when passing ?it as > a parameter. > > For example, consider the following assignment statement: > > Map> anagrams = new HashMap>(); > > This is rather lengthy, so it can be replaced with this: > > Map> anagrams = new HashMap<>(); > > Major Advantages > Generics have had a tremendously positive impact on type safety in the > Java programming language. They ?have made it possible to provide > static guarantees about the type of instances used by other classes, > preventing entire classes of runtime errors from occurring. However, > generics have added complexity to Java, making the code far more > verbose and occasionally di?cult to read. Although solving this > problem is well outside the scope of this proposal, a limited form of > type inference would remove unnecessary redundancy from the language. > > The requirement that type parameters be duplicated unnecessarily like > this encourages an unfortunate > overabundance of static factory methods, simply because type inference > works on method invocations. For > example, the Google collections library [2] contains a class that > wraps every possible constructor of every > subclass of java.util.List in the JDK: > > public class Lists { > ?public static List newArrayList() { return new ArrayList(); } > ?public static List newArrayList(int i) { return new ArrayList(i); } > ?// ... > } > List list = Lists.newArrayList(); > > This approach avoids the redundancy in the declaration, but requires > two declarations for every possible > constructor in every possible class. This is ugly: every time a > constructor or a new subtype of List is created, > this class must be updated. Furthermore, the names of these methods > does not have to be consistent; there > is no reason to favor newArrayList over createArrayList. The proposed > feature would make this approach > obsolete. > > Major Disadvantages > > As a minor change, the impact of this feature would have few > disadvantages. It does have bene?ts and > drawbacks when compared with other implementations, though. For > example, it could be argued that > inference would look cleaner without the <> token: > > Map> list = new Map(); > > Unfortunately, for the purposes of backwards compatibility, new Map() > indicates a raw type, and therefore > cannot be used for type inference. > > An argument can also be made for more full type inference: > > auto map = new HashMap(); > map.get("Foo"); // map is understood to be a Map > > or, alternatively, for a typedef like feature, where type identi?ers > are assigned to longer typenames: > > typedef MyMap HashMap>; > MyMap m = new MyMap(); > > Both of these approaches, which are present in the forthcoming C++ > standard, would eliminate a lot of > verbosity, at the expense of (potentially) obscuring the type of the > variable. Neither of these proposals are > precluded by this proposal; one, both or neither can be done at a later date. > > 2 Examples > > Here is a simple example, showing a use case for type inference for > blank ?nals. An ImmutableMap is a Map > implementation that throws an exception when mutation is attempted. In > this example, the programmer > writes > twice instead of four times, and > once instead of twice: > > class AllAnagrams { > ?final Map> anagrams; > ?AllAnagrams(List originals) { > ? ?Map> map = new HashMap<>(); // saves typing > ? ?for (String s : originals) { > ? ? ?String alphagram = alphagram(word); > ? ? ?List group = anagrams.get(alphagram); > ? ? ?if (group == null) > ? ? ? ?anagrams.put(alphagram, group = new ArrayList<>()); // saves typing > ? ? ?group.add(word); > ? ?} > ? anagrams = new ImmutableMap<>(map); // saves typing > ?} > ?private static String alphagram(String s) { > ? ?char[] chars = s.toCharArray(); > ? ?Arrays.sort(chars); > ? ?return String.valueOf(chars); > ?} > } > > Here is another example, showing a use case for type inference in > parameter passing: > class TreeNode { > ?T value; > ?TreeNode left, right; > ?private List> buildPathsInternal( > ? ?List> list, List currPath, TreeNode node) { > ? ?if (node == null) { > ? ? ?// type inference does not save typing here; see section on Wildcards. > ? ? ?list.add(new ArrayList(currPath)); > ? ? ?return list; > ? ?} > ? ?currPath.add(node); > ? ?buildPathsInternal(list, currPath, node.left); > ? ?buildPathsInternal(list, currPath, node.right); > ? ?currPath.remove(node); > ? ?return list; > ?} > ?public List> getAllPaths(TreeNode head) { > ? ?// Type inference saves typing here: > ? ?return buildPathsInternal(new ArrayList<>(), new LinkedList<>(), head); > ?} > } > > Details > > Speci?cation > Informally, the speci?cation adds syntax to replace the type arguments > < T1 ...Tn > to a class being instanti- > ated by a call to new with the simple token <>. It also provides a new > conversion that infers what the type > arguments would have been from the context, and treats the instance > creation as if those type arguments > were present. > > Syntax > The syntax of the new statement is currently given in two di?erent > ways in the Java Language Speci?cation > (JLS) [1] ?15.9 and JLS?18.1 For simplicity, we restrict ourselves to > the grammar given in ?15.9. > > ClassInstanceCreationExpression ::= > ?new TypeArguments_opt ClassOrInterfaceCreationType ( > ArgumentList_opt ) ClassBody_opt > ?Primary . new TypeArguments_opt Identifier > PossiblyInferredTypeArguments ( ArgumentList_opt ) ClassBodyopt > > ClassOrInterfaceCreationType ::= > ?TypeDeclSpecifier PossiblyInferredTypeArguments_opt > > PossiblyInferredTypeArguments ::= > ?<> > ?TypeArguments_opt > > Semantics and Compilation > Consider G1 , a generic type that is declared with 0 type arguments, and G2 > ?T1 , T2 , ..., Tn ?, a generic type > that is declared with n type arguments. There is a Type Inference > Conversion from G1 to G2 if and only if > ?? G2 ?s erased type is a supertype of G1 ?s erased type and > ?? all type arguments T1 , T2 ...Tn uniquely identify reference types > (i.e., they have no wildcard type arguments, although see below for > more discussion of this). > > A Type Inference Conversion can take place in an assignment or method > invocation conversion context > (JLS ?5). It might be possible to allow the inference to take place in > a casting conversion context; see > Section 6.1 for more discussion of this. > > Type Inference Conversions are unique in that they are not actually > performed. Instead, they are used > to replace the type they would ordinarily be converting: if a Type > Inference Conversion can take place, then > the type parameters of G1 in the conversion context are deemed to be > identical to those of type G2 . > > Compilation > The resulting bytecode would be identical to bytecode generated by the > same code with the types inferred. > > Testing > The proposed construct can be tested by writing a number of statements > that construct instances using > inferred types. These instances can then be assigned to variables and > ?elds of speci?c types, and passed to > methods that expect speci?c types. These tests should compile and run > as expected: > Set set = new SortedSet<>(); > set.add("A"); > set.add("B"); > set.add("C"); > // verify that set contains "A", "B", "C". > > Other tests can be performed by attempted to place new instances of > inferred types in contexts that > contain wildcards; these tests should fail: > > List list = new ArrayList<>(); // should fail > List list = new ArrayList<>(); > list.add("A"); > list.addAll(new ArrayList<>()); // should fail, since addAll expects > ? ?// Collection > > Library Support > No library support is required, although libraries can be rewritten to > take advantage of the new feature. > > Re?ective APIs > No re?ective APIs need to be changed. The only related API is > Class.newInstance; however, because > generics are not rei?ed in Java, this API does not take type > parameters. A compiler cannot infer non- > existent type parameters. > > Other Changes > No other parts of the platform need to be updated. > > Migration > Libraries can be rewritten to take advantage of this feature, but it > is not imperative that they do so. > > Compatibility > This change is backwards compatible. It will not make any changes to > break existing compilation strategies > or existing code. > > References > Existing Bugs: 4879776, 6242254, 5092426, 6220689, 4983159, 6368076 > > [1] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java > Language Speci?cation, 3rd Edition. > Addison Wesley, 2004. > [2] Google Inc. Google Collections Classes. > > Additional Features > > Casting Conversion > It would be possible to specify Type Inference Conversion so that it > takes place in a Cast Context: > > List emptyList() { > ?return (List) new ArrayList<>(); > } > This would keep the casting context consistent with the other > conversion contexts. However, the utility of > this is questionable, so an argument could be made that this is a > needless change. > > Wildcards > > In the method buildPathsInternal in Section 2, we need to use > ArrayList?s copy constructor to create a copy of a List, but > cannot: > > if (node == null) { > ?list.add(new ArrayList(currPath)); > ?return list; > } > > The inference does not work here because the ArrayList constructor > expects an argument of type Collection extends E>. The approach to inference described above needs to be able > to determine the exact type of > the type parameters being inferred. Since we don?t have an exact type > here, the inference will fail. > One possible tweak to our approach would be the ability to infer an > actual type parameter from a > wildcard. For example, if the least upper bound of a wildcard > expression, when evaluated, would be a legal > type parameter for the type being instantiated, we might consider > inferring that type. This would make it > possible to use type inference in the example above: > > if (node == null) { > ?// > is inferred from Collection > ?list.add(new ArrayList<>(currPath)); > ?return list; > } > > Further inference for method parameters > As pointed out above, the result of a generic method: > > public static List newArrayList() { return new ArrayList(); } > > can be used for assignment: > > List list = Lists.newArrayList(); > > Although this construct can be used for assignment, it cannot be used > in parameter passing when a type argument is required: > > public void expectStringList(List list) { > ... > } > > expectStringList(Lists.newArrayList()); // doesn?t compile > expectStringList(Lists.newArrayList()); // does compile > > The fact that inference works for assignment but not for parameter > passing is very confusing and arbitrary. > Changing this would be consistent with the way type inference is > presented in this proposal. > > From jjb at google.com Fri Feb 27 22:29:45 2009 From: jjb at google.com (Joshua Bloch) Date: Fri, 27 Feb 2009 22:29:45 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> Message-ID: <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> Automatic Resource Management *AUTHOR: *Joshua Bloch *OVERVIEW* FEATURE SUMMARY: A *resource* is as an object that must be closed manually, such as a java.io.InputStream, OutputStream, Reader, Writer, Formatter; java.nio.Channel;java.net.socket; java.sql.Connection, Statement, ResultSet, or java.awt.Graphics. The *automatic resource management statement* is a form of the try statement that declares one or more resources. The scope of these resource declarations is limited to the statement. When the statement completes, whether normally or abruptly, all of its resources are closed automatically. MAJOR ADVANTAGE: The automatic resource management statement obviates the need for manual resource termination, which has proven ugly and error prone. Even good programmers get it wrong most of the time. For example, Sun?s guide to Persistent Connections (http://tinyurl.com/6b5jc7) gets it wrong in code that claims to be exemplary. Likewise, the solution on page 88 of Bloch and Gafter?s *Java Puzzlers* (Addison-Wesley, 2006) is badly broken, and no one ever noticed. In fact, 2/3 of the uses of the close method in the JDK itself are wrong! The price for failing to terminate resources properly is resource leaks or even outright failures, which may be silent (as in *Java Puzzlers*). Even the ?correct? idioms for manual resource management are deficient: if an exception is thrown in the try block, and another when closing the resource in the finally block, the second exception supplants the first, making it difficult to determine the real cause of the trouble. While it is possible to write code to suppress the second exception in favor of the first, virtually no one does, as it is just too verbose. This is not a theoretical problem; it has greatly complicated the debugging of large systems. A secondary advantage of the automatic resource management construct is that it could emit the code to suppress the uninteresting (second) exception in favor of the interesting (first) one with no effort on the part of the programmer, and no loss to the clarity of the program. Like the for-each statement (introduced in Java 1.5), the automatic resource management statement is a small piece of syntactic sugar with a very high power-to-weight ratio. MAJOR DISADVANTAGE: Like all syntactic sugar, this construct removes a bit of Java?s ?what you see is what you get? character (?transparency?). ALTERNATIVES: The benefits of this proposal cannot be had without a language change. Absent a language change, you must close resources manually. That is why Java?s competitors have automatic resource management constructs (C# has using blocks and C++ has destructors). *EXAMPLES* SIMPLE EXAMPLE: Here is a static method to read the first line of a file, demonstrating the minimal (nearly) correct code to release a single resource today. static String readFirstLineFromFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); } } Unfortunately, if the readLine and close invocations both throw exceptions, the latter exception supplants the former. The only practical way around this today would to be to ignore any exception thrown by the close invocation. While this might be reasonable in the case of a Reader or InputStream, it would be disastrous for a Writer or OutputStream. Here?s how it would look with an automatic resource management statement: static String readFirstLineFromFile2(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path)) { return br.readLine(); } } ADVANCED EXAMPLE*:* Here is a static method to make a copy of a file, demonstrating the minimal correct code to release two resources today: static void copy(String src, String dest) throws IOException { InputStream in = new FileInputStream(src); try { OutputStream out = new FileOutputStream(dest); try { byte[] buf = new byte[8 * 1024]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } finally { out.close(); } } finally { in.close(); } } Here?s how it would look with an automatic resource management statement: static void copy(String src, String dest) throws IOException { try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest)) { byte[] buf = new byte[8192]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } } *DETAILS* * * SPECIFICATION: What follows is not intended to be a formal JLS-quality specification. It emphasizes brevity and clarity over thoroughness. SYNTAX: The production for *TryStatement* in JLS ?14.20 would be extended with this alternative: *TryStatement*: try ( *ResourceDeclarations* ) *Block Catchesopt Finallyopt* *ResourceDeclarations*: *LocalVariableDeclaration* *LocalVariableDeclaration* ; *ResourceDeclarations* * * The type of each *LocalVariableDeclaration* in a *ResourceDeclarations *must be a subtype of Disposable. Such types are known as *resource types*. SEMANTICS and COMPILATION: An automatic resource management statement with a single local variable declaration and no *Finally* or *Catches* would behave as if replaced by the following source code: { final *LocalVariableDeclaration* ; try *Block* finally { *localVar*.close(); // *localVar* is the variable declared in * LocalVariableDeclaration* } } An automatic resource management statement with multiple local variable declarations and no *Finally* or *Catches* would behave as if (recursively) replaced by the following source code: { final *LocalVariableDeclaration* ; // First variable declaration try( *ResourceDeclarations* ) *Block* finally { // Remaining resource declarations *localVar*.close(); // *localVar* is the variable declared in * LocalVariableDeclaration* } } When you initially de-sugar an automatic resource management statement with n resource declarations for n > 1, you get an automatic resource management statement with n-1 resource declarations. After n such replacements, you have n nested try-finally statements, and the de-sugaring is complete. Note that resource declarations are implicitly final. For consistency with existing constructs with implicit modifiers, it is legal (though discouraged) for the programmer to provide an explicit final modifier. Note that the close method is only called on resources whose declarations execute without throwing an exception, and that the first such exception causes the statement to complete abruptly. An automatic resource management statement with a *Finally* or *Catches* would behave as if replaced by the following code (which contains an automatic resource management statement with no *Finally* or *Catches that must be expanded as per the desugaring above*): try { try ( *ResourceDeclarations* ) *Block* } *Finallyopt Catchesopt* These simple semantics solve most of the problems described above, but they leave one problem unsolved: if the *Block* throws one exception, and the automatically generated closeinvocation throws another, the latter exception supplants the former. This could be corrected by using a slightly more complex de-sugaring for the single-local-variable-declaration form of the construct: { final LocalVariableDeclaration ; boolean #suppressSecondaryException = false; try Block catch (final Throwable #t) { #suppressSecondaryException = true; throw #t; } finally { if (#suppressSecondaryException) try { localVar.close(); } catch(Exception #ignore) { } else localVar.close(); } } The variables #t, #suppressSecondaryException, and #ignore are compiler-generated identifiers that are distinct from one and other, and from any other identifiers (compiler-generated or otherwise) that are in scope (JLS ?6.3) at the point where the automatic resource management statement occurs. This de-sugaring takes advantage of the ability to rethrow a final caught exception, which has been proposed for Java 7. The present proposal does * not* depend on this ability. In its absence, one could use a method such as sneakyThrow (*Java Puzzlers*, Puzzle 43). TYPE SYSTEM: The proposal has no effect on the type system. TESTING: The proposed construct can be tested by writing automatic resource management statements with a number of resources varying from 1 to some upper limit (say 10). Each resource can throw an exception (or not) during initialization, use, or termination. JUnit assertions are added to check that all resources opened are automatically closed, and that the correct exception (if any) is thrown. LIBRARY SUPPORT: A class must implement a designated interface to make it eligible for automatic resource management. An obvious choice would be Closeable, but unfortunately its close method is specified to throw IOException, which precludes its use in a general purpose resource management facility. It is, however, possible to retrofit Closeable with a parameterized superinterface: *package** java.lang;* */*** * * A resource that must be closed when it is no longer needed.* * ** * * @param X the type of exception thrown by the close method (or* * * {@link RuntimeException} if the close method is not permitted* * * to throw any checked exceptions).* * */* *public interface Disposable {* * void close() throws X;* *}* package java.io; public interface Closeable extends Disposable { void close() throws IOException; } Other existing interfaces can be similarly retrofitted, for example: package java.sql; interface Connection extends Disposable { void close() throws SQLException; ... // (and all the other members of the Connection interface) } REFLECTIVE APIS: This proposal has no effect on core reflective APIs. The tree API inside javac ( http://java.sun.com/javase/6/docs/jdk/api/javac/tree/index.html) would require a minor extension. OTHER CHANGES: No other parts of the platform need be to be updated. MIGRATION: Any resource that must be closed manually should be retrofitted to implement the Disposable interface. In the JDK, this includes java.io.Closeable;java.sql.Connection, Statement, and ResultSet. New code using classes that implement Disposable should use automatic resource management statements (for clarity and correctness). Manual resource management in existing code can be replaced by automatic resource management for increased clarity and improved behavior. Given the number of resource management errors observed in existing code, it may be worth the time to do this systematically. It is very easy to do this with any modern IDE, which can search for uses of a method (in this case, Disposable.close()). *COMPATIBILITY* * * BREAKING CHANGES: All previously valid programs remain valid, and their semantics is unaffected. * * EXISTING PROGRAMS: Source and class files of earlier versions are unaffected by the feature. No new overloadings or overridings can occur. *REFERENCES* * * EXISTING BUGS: 4888664, 4364906, 4331290, 4215007, 4120342. *ADDITIONAL FEATURES* Here are several features that might be added to the construct if the expert group deemed it advisable: *Retaining suppressed exceptions* - As described above, the construct simply discards exceptions that are suppressed. It would probably be better to attach them to the exception in whose favor they are being suppressed. This would entail adding two new methods to Throwable, void addSuppressedException(Throwable) and Throwable[]getSuppressedExceptions(). *Ignoring certain **close failures* - One shortcoming of the construct as described is that it does not provide a way for the programmer to indicate that exceptions thrown when closing a resource should be ignored. In the case of the copy method, ideally the program would ignore exceptions thrown when closing the InputStream, but not theOutputStream. There are several ways this could be achieved. *Expressions in place of declarations* - It was suggested that the automatic resource management statement could be defined to allow an expression in place of a variable declaration, permitting the use of preexisting variables. This feature was consciously omitted to make it more difficult to access a closed resource accidentally. *DESIGN ALTERNATIVES* *Modifier in place of block* - An alterative to a block construct is a new modifier that could be added to any local variable declaration for a variable that extends Disposable. This is more flexible and less verbose, but more dissimilar to existing Java language constructs. *Annotation to indicate termination method *- An alternative to the proposed use of the Disposable interface is an annotation on the resource termination method. This allows the use of a different method names (such as destroy and terminate) and eases the use of the new construct with existing resource types. But it is more ?magical? and does not mesh as well with Java?s type system. From jjb at google.com Fri Feb 27 22:45:40 2009 From: jjb at google.com (Joshua Bloch) Date: Fri, 27 Feb 2009 22:45:40 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> Message-ID: <17b2302a0902272245q22824deanf6ac9668c33bd0e@mail.gmail.com> Folks, I am sorry. I have a perfectly good pdf, and I just spent an hour getting a decent HTML version so I could mail you rich text, but the mailing list trashed the formatting. Please don't suffer through reading the version I just sent you! Tomorrow we will sort things out so that we can send attachments. In the mean time, I'll send a copy of the pdf to anyone who asks for it. Josh From jeremy.manson at gmail.com Fri Feb 27 22:56:53 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Fri, 27 Feb 2009 22:56:53 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> Message-ID: <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> Neal, I thought you had disappeared into the wilderness! I might not have written this if I thought that you were on the job. Anyway, it sounds as if you have an example in mind where G1 and G2 can have different type parameters. I have to say that the only ones that come to mind are the wildcard examples I give at the end of the proposal (where you have to infer the type's LUB). I was only going to pursue that if people thought it was a good idea. I imagine you have some others in mind? I did look at making modifications to the type inference algorithm, but I thought I could get away without it if you basically treat the entire operation as a conversion. It makes the proposal simpler not to have to tackle that particular issue. It seems less likely that this would be possible if G1 and G2 have to be able to have different type parameters. What do you think of the idea in the proposal for using this for casts? Do you think it makes sense to be able to say: List list = (List<>) new ArrayList(); Jeremy On Fri, Feb 27, 2009 at 10:28 PM, Neal Gafter wrote: > Jeremy- > > Where your spec says "the type parameters of G1 in the conversion > context are deemed to be identical to those of type G2" seems to > assume that the types G1 and G2 are related in a way that their type > parameters align exactly. ?That is not the case in general. ?G1 and G2 > might have different numbers of type parameters or they might have > "corresponding" parameters in a different order. > > The most significant problem with this proposal is that it completely > ignores the most difficult aspect of this feature - the required > modifications to the type inference algorithm specified in the JLS > (15.12.2.7 and 15.12.2.8). ?Joe Darcy and I discussed how to specify > that on Friday, and I believe he is preparing a proposal. > > Regards, > Neal > > On Fri, Feb 27, 2009 at 10:10 PM, Jeremy Manson wrote: >> Improved Type Inference for Generic Instance Creation >> >> (Sorry about the length; I probably got a little carried away) >> >> Author: Jeremy Manson >> >> Overview >> >> Feature Summary >> >> This proposal addresses the addition of limited type inference for >> class instance creation expressions to the Java programming language. >> In cases where parametrized types need to be explicitly declared for a >> constructor, and the full parametrized type < T1 , T2 , ...Tn > of >> that constructor is obvious from the context, then the ?parameterized >> type of the constructor can be replaced with an empty set of type >> parameters: <>. The <> ?construct is legal to use when constructing an >> ob ject and either assigning it to a variable, or when passing ?it as >> a parameter. >> >> For example, consider the following assignment statement: >> >> Map> anagrams = new HashMap>(); >> >> This is rather lengthy, so it can be replaced with this: >> >> Map> anagrams = new HashMap<>(); >> >> Major Advantages >> Generics have had a tremendously positive impact on type safety in the >> Java programming language. They ?have made it possible to provide >> static guarantees about the type of instances used by other classes, >> preventing entire classes of runtime errors from occurring. However, >> generics have added complexity to Java, making the code far more >> verbose and occasionally di?cult to read. Although solving this >> problem is well outside the scope of this proposal, a limited form of >> type inference would remove unnecessary redundancy from the language. >> >> The requirement that type parameters be duplicated unnecessarily like >> this encourages an unfortunate >> overabundance of static factory methods, simply because type inference >> works on method invocations. For >> example, the Google collections library [2] contains a class that >> wraps every possible constructor of every >> subclass of java.util.List in the JDK: >> >> public class Lists { >> ?public static List newArrayList() { return new ArrayList(); } >> ?public static List newArrayList(int i) { return new ArrayList(i); } >> ?// ... >> } >> List list = Lists.newArrayList(); >> >> This approach avoids the redundancy in the declaration, but requires >> two declarations for every possible >> constructor in every possible class. This is ugly: every time a >> constructor or a new subtype of List is created, >> this class must be updated. Furthermore, the names of these methods >> does not have to be consistent; there >> is no reason to favor newArrayList over createArrayList. The proposed >> feature would make this approach >> obsolete. >> >> Major Disadvantages >> >> As a minor change, the impact of this feature would have few >> disadvantages. It does have bene?ts and >> drawbacks when compared with other implementations, though. For >> example, it could be argued that >> inference would look cleaner without the <> token: >> >> Map> list = new Map(); >> >> Unfortunately, for the purposes of backwards compatibility, new Map() >> indicates a raw type, and therefore >> cannot be used for type inference. >> >> An argument can also be made for more full type inference: >> >> auto map = new HashMap(); >> map.get("Foo"); // map is understood to be a Map >> >> or, alternatively, for a typedef like feature, where type identi?ers >> are assigned to longer typenames: >> >> typedef MyMap HashMap>; >> MyMap m = new MyMap(); >> >> Both of these approaches, which are present in the forthcoming C++ >> standard, would eliminate a lot of >> verbosity, at the expense of (potentially) obscuring the type of the >> variable. Neither of these proposals are >> precluded by this proposal; one, both or neither can be done at a later date. >> >> 2 Examples >> >> Here is a simple example, showing a use case for type inference for >> blank ?nals. An ImmutableMap is a Map >> implementation that throws an exception when mutation is attempted. In >> this example, the programmer >> writes > twice instead of four times, and >> once instead of twice: >> >> class AllAnagrams { >> ?final Map> anagrams; >> ?AllAnagrams(List originals) { >> ? ?Map> map = new HashMap<>(); // saves typing >> ? ?for (String s : originals) { >> ? ? ?String alphagram = alphagram(word); >> ? ? ?List group = anagrams.get(alphagram); >> ? ? ?if (group == null) >> ? ? ? ?anagrams.put(alphagram, group = new ArrayList<>()); // saves typing >> ? ? ?group.add(word); >> ? ?} >> ? anagrams = new ImmutableMap<>(map); // saves typing >> ?} >> ?private static String alphagram(String s) { >> ? ?char[] chars = s.toCharArray(); >> ? ?Arrays.sort(chars); >> ? ?return String.valueOf(chars); >> ?} >> } >> >> Here is another example, showing a use case for type inference in >> parameter passing: >> class TreeNode { >> ?T value; >> ?TreeNode left, right; >> ?private List> buildPathsInternal( >> ? ?List> list, List currPath, TreeNode node) { >> ? ?if (node == null) { >> ? ? ?// type inference does not save typing here; see section on Wildcards. >> ? ? ?list.add(new ArrayList(currPath)); >> ? ? ?return list; >> ? ?} >> ? ?currPath.add(node); >> ? ?buildPathsInternal(list, currPath, node.left); >> ? ?buildPathsInternal(list, currPath, node.right); >> ? ?currPath.remove(node); >> ? ?return list; >> ?} >> ?public List> getAllPaths(TreeNode head) { >> ? ?// Type inference saves typing here: >> ? ?return buildPathsInternal(new ArrayList<>(), new LinkedList<>(), head); >> ?} >> } >> >> Details >> >> Speci?cation >> Informally, the speci?cation adds syntax to replace the type arguments >> < T1 ...Tn > to a class being instanti- >> ated by a call to new with the simple token <>. It also provides a new >> conversion that infers what the type >> arguments would have been from the context, and treats the instance >> creation as if those type arguments >> were present. >> >> Syntax >> The syntax of the new statement is currently given in two di?erent >> ways in the Java Language Speci?cation >> (JLS) [1] ?15.9 and JLS?18.1 For simplicity, we restrict ourselves to >> the grammar given in ?15.9. >> >> ClassInstanceCreationExpression ::= >> ?new TypeArguments_opt ClassOrInterfaceCreationType ( >> ArgumentList_opt ) ClassBody_opt >> ?Primary . new TypeArguments_opt Identifier >> PossiblyInferredTypeArguments ( ArgumentList_opt ) ClassBodyopt >> >> ClassOrInterfaceCreationType ::= >> ?TypeDeclSpecifier PossiblyInferredTypeArguments_opt >> >> PossiblyInferredTypeArguments ::= >> ?<> >> ?TypeArguments_opt >> >> Semantics and Compilation >> Consider G1 , a generic type that is declared with 0 type arguments, and G2 >> ?T1 , T2 , ..., Tn ?, a generic type >> that is declared with n type arguments. There is a Type Inference >> Conversion from G1 to G2 if and only if >> ?? G2 ?s erased type is a supertype of G1 ?s erased type and >> ?? all type arguments T1 , T2 ...Tn uniquely identify reference types >> (i.e., they have no wildcard type arguments, although see below for >> more discussion of this). >> >> A Type Inference Conversion can take place in an assignment or method >> invocation conversion context >> (JLS ?5). It might be possible to allow the inference to take place in >> a casting conversion context; see >> Section 6.1 for more discussion of this. >> >> Type Inference Conversions are unique in that they are not actually >> performed. Instead, they are used >> to replace the type they would ordinarily be converting: if a Type >> Inference Conversion can take place, then >> the type parameters of G1 in the conversion context are deemed to be >> identical to those of type G2 . >> >> Compilation >> The resulting bytecode would be identical to bytecode generated by the >> same code with the types inferred. >> >> Testing >> The proposed construct can be tested by writing a number of statements >> that construct instances using >> inferred types. These instances can then be assigned to variables and >> ?elds of speci?c types, and passed to >> methods that expect speci?c types. These tests should compile and run >> as expected: >> Set set = new SortedSet<>(); >> set.add("A"); >> set.add("B"); >> set.add("C"); >> // verify that set contains "A", "B", "C". >> >> Other tests can be performed by attempted to place new instances of >> inferred types in contexts that >> contain wildcards; these tests should fail: >> >> List list = new ArrayList<>(); // should fail >> List list = new ArrayList<>(); >> list.add("A"); >> list.addAll(new ArrayList<>()); // should fail, since addAll expects >> ? ?// Collection >> >> Library Support >> No library support is required, although libraries can be rewritten to >> take advantage of the new feature. >> >> Re?ective APIs >> No re?ective APIs need to be changed. The only related API is >> Class.newInstance; however, because >> generics are not rei?ed in Java, this API does not take type >> parameters. A compiler cannot infer non- >> existent type parameters. >> >> Other Changes >> No other parts of the platform need to be updated. >> >> Migration >> Libraries can be rewritten to take advantage of this feature, but it >> is not imperative that they do so. >> >> Compatibility >> This change is backwards compatible. It will not make any changes to >> break existing compilation strategies >> or existing code. >> >> References >> Existing Bugs: 4879776, 6242254, 5092426, 6220689, 4983159, 6368076 >> >> [1] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java >> Language Speci?cation, 3rd Edition. >> Addison Wesley, 2004. >> [2] Google Inc. Google Collections Classes. >> >> Additional Features >> >> Casting Conversion >> It would be possible to specify Type Inference Conversion so that it >> takes place in a Cast Context: >> >> List emptyList() { >> ?return (List) new ArrayList<>(); >> } >> This would keep the casting context consistent with the other >> conversion contexts. However, the utility of >> this is questionable, so an argument could be made that this is a >> needless change. >> >> Wildcards >> >> In the method buildPathsInternal in Section 2, we need to use >> ArrayList?s copy constructor to create a copy of a List, but >> cannot: >> >> if (node == null) { >> ?list.add(new ArrayList(currPath)); >> ?return list; >> } >> >> The inference does not work here because the ArrayList constructor >> expects an argument of type Collection> extends E>. The approach to inference described above needs to be able >> to determine the exact type of >> the type parameters being inferred. Since we don?t have an exact type >> here, the inference will fail. >> One possible tweak to our approach would be the ability to infer an >> actual type parameter from a >> wildcard. For example, if the least upper bound of a wildcard >> expression, when evaluated, would be a legal >> type parameter for the type being instantiated, we might consider >> inferring that type. This would make it >> possible to use type inference in the example above: >> >> if (node == null) { >> ?// > is inferred from Collection >> ?list.add(new ArrayList<>(currPath)); >> ?return list; >> } >> >> Further inference for method parameters >> As pointed out above, the result of a generic method: >> >> public static List newArrayList() { return new ArrayList(); } >> >> can be used for assignment: >> >> List list = Lists.newArrayList(); >> >> Although this construct can be used for assignment, it cannot be used >> in parameter passing when a type argument is required: >> >> public void expectStringList(List list) { >> ... >> } >> >> expectStringList(Lists.newArrayList()); // doesn?t compile >> expectStringList(Lists.newArrayList()); // does compile >> >> The fact that inference works for assignment but not for parameter >> passing is very confusing and arbitrary. >> Changing this would be consistent with the way type inference is >> presented in this proposal. >> >> > From neal at gafter.com Fri Feb 27 23:20:34 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 23:20:34 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> Message-ID: <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> The proposed changes to existing APIs introduce an incompatibility. This, for example, is legal today: interface A extends java.sql.Connection, java.io.Closeable {} However, since you propose that Connection would extend Disposable and Closable would extend Disposable, interface A is broken after the proposed change. Also, the changes you propose to existing APIs introduce changes to overload resolution that can break existing code. You also missed a few disadvantages. o All of the difficult decisions that you defer to the expert group, such as the handling of exceptions, suggest that this solution is likely to be a poor match for many uses, resulting in the sort of shoehorning of code into the construct that results in errors. o This approach of adding point solutions one-by-one to a language for particular use cases results in a general degradation of the quality of the language over time with little lifting of the level of abstraction, so any change of this sort should be viewed with great skepticism. o Given the short time frame that project coin is to complete its work and the nature of this solution -- attempting to maximize the utility in the most common use cases while minimizing the likelihood of user error in using the construct -- it seems unlikely that we will not have the time to experiment with all the variables in realistic contexts. Therefore, one should add to the disadvantages the very real chance that the language construct is likely to get some of these aspects wrong if added in the JDK7 timeframe. The fact that these issues haven't been resolved in the 32+ months since you started working on this proposal, or in the 13+ months since a prototype has been available, suggests that 3-6 months is not a reasonable timeframe to resolve them, and even hints that there may be no generally acceptable solution. You also forgot to mention the obvious alternatives. Most prominently, control abstraction via closures (BGGA or JCA) allows API designers to tune the behavior for the various use cases (APIs) without the need for point-solution API-specific language changes. Generally, this proposal appears to leave too many open issues to be suitable for inclusion in the coin project/JSR. On Fri, Feb 27, 2009 at 10:29 PM, Joshua Bloch wrote: > Automatic Resource Management > > *AUTHOR: *Joshua Bloch > > *OVERVIEW* > > FEATURE SUMMARY: A *resource* is as an object that must be closed manually, > such as a java.io.InputStream, OutputStream, Reader, Writer, Formatter; > java.nio.Channel;java.net.socket; java.sql.Connection, Statement, ResultSet, > or java.awt.Graphics. > > The *automatic resource management statement* is a form of the try statement > that declares one or more resources. The scope of these resource > declarations is limited to the statement. When the statement completes, > whether normally or abruptly, all of its resources are closed automatically. > > MAJOR ADVANTAGE: The automatic resource management statement obviates the > need for manual resource termination, which has proven ugly and error prone. > Even good programmers get it wrong most of the time. For example, Sun?s > guide to Persistent Connections (http://tinyurl.com/6b5jc7) gets it wrong in > code that claims to be exemplary. Likewise, the solution on page 88 of Bloch > and Gafter?s *Java Puzzlers* (Addison-Wesley, 2006) is badly broken, and no > one ever noticed. In fact, 2/3 of the uses of the close method in the JDK > itself are wrong! The price for failing to terminate resources properly is > resource leaks or even outright failures, which may be silent (as in *Java > Puzzlers*). > > Even the ?correct? idioms for manual resource management are deficient: if > an exception is thrown in the try block, and another when closing the > resource in the finally block, the second exception supplants the first, > making it difficult to determine the real cause of the trouble. While it is > possible to write code to suppress the second exception in favor of the > first, virtually no one does, as it is just too verbose. This is not a > theoretical problem; it has greatly complicated the debugging of large > systems. > > A secondary advantage of the automatic resource management construct is that > it could emit the code to suppress the uninteresting (second) exception in > favor of the interesting (first) one with no effort on the part of the > programmer, and no loss to the clarity of the program. > > Like the for-each statement (introduced in Java 1.5), the automatic resource > management statement is a small piece of syntactic sugar with a very high > power-to-weight ratio. > > MAJOR DISADVANTAGE: Like all syntactic sugar, this construct removes a bit > of Java?s ?what you see is what you get? character (?transparency?). > > ALTERNATIVES: The benefits of this proposal cannot be had without a language > change. Absent a language change, you must close resources manually. That is > why Java?s competitors have automatic resource management constructs (C# > has using blocks and C++ has destructors). > > *EXAMPLES* > > SIMPLE EXAMPLE: Here is a static method to read the first line of a file, > demonstrating the minimal (nearly) correct code to release a single resource > today. > > ? ?static String readFirstLineFromFile(String path) throws IOException { > > ? ? ? ?BufferedReader br = new BufferedReader(new FileReader(path)); > > ? ? ? ?try { > > ? ? ? ? ? ?return br.readLine(); > > ? ? ? ?} finally { > > ? ? ? ? ? ?br.close(); > > ? ? ? ?} > > ? ?} > > Unfortunately, if the readLine and close invocations both throw exceptions, > the latter exception supplants the former. ?The only practical way around > this today would to be to ignore any exception thrown by the close invocation. > While this might be reasonable in the case of a Reader or InputStream, it > would be disastrous for a Writer or OutputStream. > > Here?s how it would look with an automatic resource management statement: > > > > ? ?static String readFirstLineFromFile2(String path) throws IOException { > > ? ? ? ?try (BufferedReader br = new BufferedReader(new FileReader(path)) { > > ? ? ? ? ? return br.readLine(); > > ? ? ? ?} > > ? ?} > > ADVANCED EXAMPLE*:* Here is a static method to make a copy of a file, > demonstrating the minimal correct code to release two resources today: > > ? ?static void copy(String src, String dest) throws IOException { > > ? ? ? ?InputStream in = new FileInputStream(src); > > ? ? ? ?try { > > ? ? ? ? ? ?OutputStream out = new FileOutputStream(dest); > > ? ? ? ? ? ?try { > > ? ? ? ? ? ? ? ?byte[] buf = new byte[8 * 1024]; > > ? ? ? ? ? ? ? ?int n; > > ? ? ? ? ? ? ? ?while ((n = in.read(buf)) >= 0) > > ? ? ? ? ? ? ? ? ? ?out.write(buf, 0, n); > > ? ? ? ? ? ?} finally { > > ? ? ? ? ? ? ? ?out.close(); > > ? ? ? ? ? ?} > > ? ? ? ?} finally { > > ? ? ? ? ? ?in.close(); > > ? ? ? ?} > > ? ?} > > Here?s how it would look with an automatic resource management statement: > > ? ?static void copy(String src, String dest) throws IOException { > > ? ? ? ?try (InputStream in = new FileInputStream(src); > > ? ? ? ? ? ? OutputStream out = new FileOutputStream(dest)) { > > ? ? ? ? ? ?byte[] buf = new byte[8192]; > > ? ? ? ? ? ?int n; > > ? ? ? ? ? ?while ((n = in.read(buf)) >= 0) > > ? ? ? ? ? ? ? ?out.write(buf, 0, n); > > ? ? ? ?} > > ? ?} > > > > *DETAILS* > > * * > > SPECIFICATION: What follows is not intended to be a formal JLS-quality > specification. It emphasizes brevity and clarity over thoroughness. > > > > SYNTAX: The production for *TryStatement* in JLS ?14.20 would be extended > with this alternative: > > > > *TryStatement*: > > ? ?try ( *ResourceDeclarations* ) *Block Catchesopt Finallyopt* > > *ResourceDeclarations*: > > ? ?*LocalVariableDeclaration* > > ? ?*LocalVariableDeclaration* ; *ResourceDeclarations* > > * * > > The type of each *LocalVariableDeclaration* in a *ResourceDeclarations *must > be a subtype of Disposable. ?Such types are known as *resource types*. > > > > SEMANTICS and COMPILATION: An automatic resource management statement with a > single local variable declaration and no *Finally* or *Catches* would behave > as if replaced by the following source code: > > > > { > > ? ?final *LocalVariableDeclaration* ; > > ? ?try *Block* finally { > > ? ? ? ?*localVar*.close(); ?// *localVar* is the variable declared in * > LocalVariableDeclaration* > > ? ?} > > } > > > > An automatic resource management statement with multiple local variable > declarations and no *Finally* or *Catches* would behave as if (recursively) > replaced by the following source code: > > > > { > > ? ?final *LocalVariableDeclaration* ; ? ? ? ? ? ? ?// First variable > declaration > > ? ?try( *ResourceDeclarations* ) *Block* finally { ?// Remaining resource > declarations > > ? ? ? ?*localVar*.close(); ?// *localVar* is the variable declared in * > LocalVariableDeclaration* > > ? ?} > > } > > > > When you initially de-sugar an automatic resource management statement with > n resource declarations for n > 1, you get an automatic resource management > statement with n-1 resource declarations. After n such replacements, you > have n nested try-finally statements, and the de-sugaring is complete. Note > that resource declarations are implicitly final. For consistency with > existing constructs with implicit modifiers, it is legal (though > discouraged) for the programmer to provide an explicit final modifier. > > > > Note that the close method is only called on resources whose declarations > execute without throwing an exception, and that the first such exception > causes the statement to complete abruptly. > > > > An automatic resource management statement with a *Finally* or *Catches* would > behave as if replaced by the following code (which contains an automatic > resource management statement with no *Finally* or *Catches that must be > expanded as per the desugaring above*): > > > > try { > > ? ?try ( *ResourceDeclarations* ) *Block* > > } *Finallyopt Catchesopt* > > > > These simple semantics solve most of the problems described above, but they > leave one problem unsolved: if the *Block* throws one exception, and the > automatically generated closeinvocation throws another, the latter exception > supplants the former. ?This could be corrected by using a slightly more > complex de-sugaring for the single-local-variable-declaration form of the > construct: > > > > { > > ? ?final LocalVariableDeclaration ; > > ? ?boolean #suppressSecondaryException = false; > > ? ?try Block catch (final Throwable #t) { > > ? ? ? ?#suppressSecondaryException = true; > > ? ? ? ?throw #t; > > ? ?} finally { > > ? ? ? ?if (#suppressSecondaryException) > > ? ? ? ? ? ?try { localVar.close(); } catch(Exception #ignore) { } > > ? ? ? ?else > > ? ? ? ? ? ?localVar.close(); > > ? ?} > > } > > > > The variables #t, #suppressSecondaryException, and #ignore are > compiler-generated identifiers that are distinct from one and other, and > from any other identifiers (compiler-generated or otherwise) that are in > scope (JLS ?6.3) at the point where the automatic resource management > statement occurs. > > This de-sugaring takes advantage of the ability to rethrow a final caught > exception, which has been proposed for Java 7. ?The present proposal does * > not* depend on this ability. ?In its absence, one could use a method such > as sneakyThrow (*Java Puzzlers*, Puzzle 43). > > > > TYPE SYSTEM: The proposal has no effect on the type system. > > > > TESTING: The proposed construct can be tested by writing automatic resource > management statements with a number of resources varying from 1 to some > upper limit (say 10). Each resource can throw an exception (or not) during > initialization, use, or termination. JUnit assertions are added to check > that all resources opened are automatically closed, and that the correct > exception (if any) is thrown. > > > > LIBRARY SUPPORT: A class must implement a designated interface to make it > eligible for automatic resource management. An obvious choice would be > Closeable, but unfortunately its close method is specified to throw > IOException, which precludes its use in a general purpose resource > management facility. It is, however, possible to retrofit Closeable with a > parameterized superinterface: > > > > *package** java.lang;* > > */*** > > * * A resource that must be closed when it is no longer needed.* > > * ** > > * * @param X the type of exception thrown by the close method (or* > > * * ? ? {@link RuntimeException} if the close method is not permitted* > > * * ? ? to throw any checked exceptions).* > > * */* > > *public interface Disposable {* > > * ? ?void close() throws X;* > > *}* > > > > package java.io; > > public interface Closeable extends Disposable { > > ? ?void close() throws IOException; > > } > > > > Other existing interfaces can be similarly retrofitted, for example: > > > > package java.sql; > > interface Connection extends Disposable { > > ? ?void close() throws SQLException; > > ? ?... ? ?// (and all the other members of the Connection interface) > > } > > > > REFLECTIVE APIS: This proposal has no effect on core reflective APIs. The > tree API inside javac ( > http://java.sun.com/javase/6/docs/jdk/api/javac/tree/index.html) would > require a minor extension. > > > > OTHER CHANGES: No other parts of the platform need be to be updated. > > > > MIGRATION: Any resource that must be closed manually should be retrofitted > to implement the Disposable interface. ?In the JDK, this includes > java.io.Closeable;java.sql.Connection, Statement, and ResultSet. New code > using classes that implement Disposable should use automatic resource > management statements (for clarity and correctness). ?Manual resource > management in existing code can be replaced by automatic resource management > for increased clarity and improved behavior. Given the number of resource > management errors observed in existing code, it may be worth the time to do > this systematically. ?It is very easy to do this with any modern IDE, which > can search for uses of a method (in this case, Disposable.close()). > > > > *COMPATIBILITY* > > * * > > BREAKING CHANGES: All previously valid programs remain valid, and their > semantics is unaffected. > > * * > > EXISTING PROGRAMS: Source and class files of earlier versions are unaffected > by the feature. ?No new overloadings or overridings can occur. > > *REFERENCES* > > * * > > EXISTING BUGS: 4888664, 4364906, 4331290, 4215007, 4120342. > > > > *ADDITIONAL FEATURES* > > > > Here are several features that might be added to the construct if the expert > group deemed it advisable: > > > > *Retaining suppressed exceptions* - As described above, the construct simply > discards exceptions that are suppressed. It would probably be better to > attach them to the exception in whose favor they are being suppressed. This > would entail adding two new methods to Throwable, void > addSuppressedException(Throwable) and Throwable[]getSuppressedExceptions(). > > > > *Ignoring certain **close failures* - One shortcoming of the construct as > described is that it does not provide a way for the programmer to indicate > that exceptions thrown when closing a resource should be ignored. In the > case of the copy method, ideally the program would ignore exceptions thrown > when closing the InputStream, but not theOutputStream. ?There are several > ways this could be achieved. > > > > *Expressions in place of declarations* - It was suggested that the automatic > resource management statement could be defined to allow an expression in > place of a variable declaration, permitting the use of preexisting > variables. ?This feature was consciously omitted to make it more difficult > to access a closed resource accidentally. > > > > *DESIGN ALTERNATIVES* > > > > *Modifier in place of block* - An alterative to a block construct is a new > modifier that could be added to any local variable declaration for a > variable that extends Disposable. ?This is more flexible and less verbose, > but more dissimilar to existing Java language constructs. > > > > *Annotation to indicate termination method *- An alternative to the proposed > use of the Disposable interface is an annotation on the resource termination > method. This allows the use of a different method names (such as destroy > ?and terminate) and eases the use of the new construct with existing > resource types. ?But it is more ?magical? and does not mesh as well with > Java?s type system. > > From neal at gafter.com Fri Feb 27 23:33:39 2009 From: neal at gafter.com (Neal Gafter) Date: Fri, 27 Feb 2009 23:33:39 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> Message-ID: <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> Adding conversions doesn't make type inference work. Each conversion that you want to affect type inference has to be accommodated specifically in the type inference algorithm. I disagree with your suggestion that this should fail: List list = new ArrayList<>(); // should fail The equivalent code using static factories works just fine. It isn't clear why this feature should behave differently, or what part of your specification makes it fail. I don't think supporting casts adds value to the feature. You can already assign, for example, from ArrayList to List without a cast. If you want to hear about the approach that Joe is working on, I'll be happy to describe it in person at your convenience (with Joe, if he wants). On Fri, Feb 27, 2009 at 10:56 PM, Jeremy Manson wrote: > Neal, > > I thought you had disappeared into the wilderness! ?I might not have > written this if I thought that you were on the job. > > Anyway, it sounds as if you have an example in mind where G1 and G2 > can have different type parameters. ?I have to say that the only ones > that come to mind are the wildcard examples I give at the end of the > proposal (where you have to infer the type's LUB). ?I was only going > to pursue that if people thought it was a good idea. ?I imagine you > have some others in mind? > > I did look at making modifications to the type inference algorithm, > but I thought I could get away without it if you basically treat the > entire operation as a conversion. ?It makes the proposal simpler not > to have to tackle that particular issue. ?It seems less likely that > this would be possible if G1 and G2 have to be able to have different > type parameters. > > What do you think of the idea in the proposal for using this for > casts? ?Do you think it makes sense to be able to say: > > List list = (List<>) new ArrayList(); > > Jeremy > > On Fri, Feb 27, 2009 at 10:28 PM, Neal Gafter wrote: >> Jeremy- >> >> Where your spec says "the type parameters of G1 in the conversion >> context are deemed to be identical to those of type G2" seems to >> assume that the types G1 and G2 are related in a way that their type >> parameters align exactly. ?That is not the case in general. ?G1 and G2 >> might have different numbers of type parameters or they might have >> "corresponding" parameters in a different order. >> >> The most significant problem with this proposal is that it completely >> ignores the most difficult aspect of this feature - the required >> modifications to the type inference algorithm specified in the JLS >> (15.12.2.7 and 15.12.2.8). ?Joe Darcy and I discussed how to specify >> that on Friday, and I believe he is preparing a proposal. >> >> Regards, >> Neal >> >> On Fri, Feb 27, 2009 at 10:10 PM, Jeremy Manson wrote: >>> Improved Type Inference for Generic Instance Creation >>> >>> (Sorry about the length; I probably got a little carried away) >>> >>> Author: Jeremy Manson >>> >>> Overview >>> >>> Feature Summary >>> >>> This proposal addresses the addition of limited type inference for >>> class instance creation expressions to the Java programming language. >>> In cases where parametrized types need to be explicitly declared for a >>> constructor, and the full parametrized type < T1 , T2 , ...Tn > of >>> that constructor is obvious from the context, then the ?parameterized >>> type of the constructor can be replaced with an empty set of type >>> parameters: <>. The <> ?construct is legal to use when constructing an >>> ob ject and either assigning it to a variable, or when passing ?it as >>> a parameter. >>> >>> For example, consider the following assignment statement: >>> >>> Map> anagrams = new HashMap>(); >>> >>> This is rather lengthy, so it can be replaced with this: >>> >>> Map> anagrams = new HashMap<>(); >>> >>> Major Advantages >>> Generics have had a tremendously positive impact on type safety in the >>> Java programming language. They ?have made it possible to provide >>> static guarantees about the type of instances used by other classes, >>> preventing entire classes of runtime errors from occurring. However, >>> generics have added complexity to Java, making the code far more >>> verbose and occasionally di?cult to read. Although solving this >>> problem is well outside the scope of this proposal, a limited form of >>> type inference would remove unnecessary redundancy from the language. >>> >>> The requirement that type parameters be duplicated unnecessarily like >>> this encourages an unfortunate >>> overabundance of static factory methods, simply because type inference >>> works on method invocations. For >>> example, the Google collections library [2] contains a class that >>> wraps every possible constructor of every >>> subclass of java.util.List in the JDK: >>> >>> public class Lists { >>> ?public static List newArrayList() { return new ArrayList(); } >>> ?public static List newArrayList(int i) { return new ArrayList(i); } >>> ?// ... >>> } >>> List list = Lists.newArrayList(); >>> >>> This approach avoids the redundancy in the declaration, but requires >>> two declarations for every possible >>> constructor in every possible class. This is ugly: every time a >>> constructor or a new subtype of List is created, >>> this class must be updated. Furthermore, the names of these methods >>> does not have to be consistent; there >>> is no reason to favor newArrayList over createArrayList. The proposed >>> feature would make this approach >>> obsolete. >>> >>> Major Disadvantages >>> >>> As a minor change, the impact of this feature would have few >>> disadvantages. It does have bene?ts and >>> drawbacks when compared with other implementations, though. For >>> example, it could be argued that >>> inference would look cleaner without the <> token: >>> >>> Map> list = new Map(); >>> >>> Unfortunately, for the purposes of backwards compatibility, new Map() >>> indicates a raw type, and therefore >>> cannot be used for type inference. >>> >>> An argument can also be made for more full type inference: >>> >>> auto map = new HashMap(); >>> map.get("Foo"); // map is understood to be a Map >>> >>> or, alternatively, for a typedef like feature, where type identi?ers >>> are assigned to longer typenames: >>> >>> typedef MyMap HashMap>; >>> MyMap m = new MyMap(); >>> >>> Both of these approaches, which are present in the forthcoming C++ >>> standard, would eliminate a lot of >>> verbosity, at the expense of (potentially) obscuring the type of the >>> variable. Neither of these proposals are >>> precluded by this proposal; one, both or neither can be done at a later date. >>> >>> 2 Examples >>> >>> Here is a simple example, showing a use case for type inference for >>> blank ?nals. An ImmutableMap is a Map >>> implementation that throws an exception when mutation is attempted. In >>> this example, the programmer >>> writes > twice instead of four times, and >>> once instead of twice: >>> >>> class AllAnagrams { >>> ?final Map> anagrams; >>> ?AllAnagrams(List originals) { >>> ? ?Map> map = new HashMap<>(); // saves typing >>> ? ?for (String s : originals) { >>> ? ? ?String alphagram = alphagram(word); >>> ? ? ?List group = anagrams.get(alphagram); >>> ? ? ?if (group == null) >>> ? ? ? ?anagrams.put(alphagram, group = new ArrayList<>()); // saves typing >>> ? ? ?group.add(word); >>> ? ?} >>> ? anagrams = new ImmutableMap<>(map); // saves typing >>> ?} >>> ?private static String alphagram(String s) { >>> ? ?char[] chars = s.toCharArray(); >>> ? ?Arrays.sort(chars); >>> ? ?return String.valueOf(chars); >>> ?} >>> } >>> >>> Here is another example, showing a use case for type inference in >>> parameter passing: >>> class TreeNode { >>> ?T value; >>> ?TreeNode left, right; >>> ?private List> buildPathsInternal( >>> ? ?List> list, List currPath, TreeNode node) { >>> ? ?if (node == null) { >>> ? ? ?// type inference does not save typing here; see section on Wildcards. >>> ? ? ?list.add(new ArrayList(currPath)); >>> ? ? ?return list; >>> ? ?} >>> ? ?currPath.add(node); >>> ? ?buildPathsInternal(list, currPath, node.left); >>> ? ?buildPathsInternal(list, currPath, node.right); >>> ? ?currPath.remove(node); >>> ? ?return list; >>> ?} >>> ?public List> getAllPaths(TreeNode head) { >>> ? ?// Type inference saves typing here: >>> ? ?return buildPathsInternal(new ArrayList<>(), new LinkedList<>(), head); >>> ?} >>> } >>> >>> Details >>> >>> Speci?cation >>> Informally, the speci?cation adds syntax to replace the type arguments >>> < T1 ...Tn > to a class being instanti- >>> ated by a call to new with the simple token <>. It also provides a new >>> conversion that infers what the type >>> arguments would have been from the context, and treats the instance >>> creation as if those type arguments >>> were present. >>> >>> Syntax >>> The syntax of the new statement is currently given in two di?erent >>> ways in the Java Language Speci?cation >>> (JLS) [1] ?15.9 and JLS?18.1 For simplicity, we restrict ourselves to >>> the grammar given in ?15.9. >>> >>> ClassInstanceCreationExpression ::= >>> ?new TypeArguments_opt ClassOrInterfaceCreationType ( >>> ArgumentList_opt ) ClassBody_opt >>> ?Primary . new TypeArguments_opt Identifier >>> PossiblyInferredTypeArguments ( ArgumentList_opt ) ClassBodyopt >>> >>> ClassOrInterfaceCreationType ::= >>> ?TypeDeclSpecifier PossiblyInferredTypeArguments_opt >>> >>> PossiblyInferredTypeArguments ::= >>> ?<> >>> ?TypeArguments_opt >>> >>> Semantics and Compilation >>> Consider G1 , a generic type that is declared with 0 type arguments, and G2 >>> ?T1 , T2 , ..., Tn ?, a generic type >>> that is declared with n type arguments. There is a Type Inference >>> Conversion from G1 to G2 if and only if >>> ?? G2 ?s erased type is a supertype of G1 ?s erased type and >>> ?? all type arguments T1 , T2 ...Tn uniquely identify reference types >>> (i.e., they have no wildcard type arguments, although see below for >>> more discussion of this). >>> >>> A Type Inference Conversion can take place in an assignment or method >>> invocation conversion context >>> (JLS ?5). It might be possible to allow the inference to take place in >>> a casting conversion context; see >>> Section 6.1 for more discussion of this. >>> >>> Type Inference Conversions are unique in that they are not actually >>> performed. Instead, they are used >>> to replace the type they would ordinarily be converting: if a Type >>> Inference Conversion can take place, then >>> the type parameters of G1 in the conversion context are deemed to be >>> identical to those of type G2 . >>> >>> Compilation >>> The resulting bytecode would be identical to bytecode generated by the >>> same code with the types inferred. >>> >>> Testing >>> The proposed construct can be tested by writing a number of statements >>> that construct instances using >>> inferred types. These instances can then be assigned to variables and >>> ?elds of speci?c types, and passed to >>> methods that expect speci?c types. These tests should compile and run >>> as expected: >>> Set set = new SortedSet<>(); >>> set.add("A"); >>> set.add("B"); >>> set.add("C"); >>> // verify that set contains "A", "B", "C". >>> >>> Other tests can be performed by attempted to place new instances of >>> inferred types in contexts that >>> contain wildcards; these tests should fail: >>> >>> List list = new ArrayList<>(); // should fail >>> List list = new ArrayList<>(); >>> list.add("A"); >>> list.addAll(new ArrayList<>()); // should fail, since addAll expects >>> ? ?// Collection >>> >>> Library Support >>> No library support is required, although libraries can be rewritten to >>> take advantage of the new feature. >>> >>> Re?ective APIs >>> No re?ective APIs need to be changed. The only related API is >>> Class.newInstance; however, because >>> generics are not rei?ed in Java, this API does not take type >>> parameters. A compiler cannot infer non- >>> existent type parameters. >>> >>> Other Changes >>> No other parts of the platform need to be updated. >>> >>> Migration >>> Libraries can be rewritten to take advantage of this feature, but it >>> is not imperative that they do so. >>> >>> Compatibility >>> This change is backwards compatible. It will not make any changes to >>> break existing compilation strategies >>> or existing code. >>> >>> References >>> Existing Bugs: 4879776, 6242254, 5092426, 6220689, 4983159, 6368076 >>> >>> [1] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java >>> Language Speci?cation, 3rd Edition. >>> Addison Wesley, 2004. >>> [2] Google Inc. Google Collections Classes. >>> >>> Additional Features >>> >>> Casting Conversion >>> It would be possible to specify Type Inference Conversion so that it >>> takes place in a Cast Context: >>> >>> List emptyList() { >>> ?return (List) new ArrayList<>(); >>> } >>> This would keep the casting context consistent with the other >>> conversion contexts. However, the utility of >>> this is questionable, so an argument could be made that this is a >>> needless change. >>> >>> Wildcards >>> >>> In the method buildPathsInternal in Section 2, we need to use >>> ArrayList?s copy constructor to create a copy of a List, but >>> cannot: >>> >>> if (node == null) { >>> ?list.add(new ArrayList(currPath)); >>> ?return list; >>> } >>> >>> The inference does not work here because the ArrayList constructor >>> expects an argument of type Collection>> extends E>. The approach to inference described above needs to be able >>> to determine the exact type of >>> the type parameters being inferred. Since we don?t have an exact type >>> here, the inference will fail. >>> One possible tweak to our approach would be the ability to infer an >>> actual type parameter from a >>> wildcard. For example, if the least upper bound of a wildcard >>> expression, when evaluated, would be a legal >>> type parameter for the type being instantiated, we might consider >>> inferring that type. This would make it >>> possible to use type inference in the example above: >>> >>> if (node == null) { >>> ?// > is inferred from Collection >>> ?list.add(new ArrayList<>(currPath)); >>> ?return list; >>> } >>> >>> Further inference for method parameters >>> As pointed out above, the result of a generic method: >>> >>> public static List newArrayList() { return new ArrayList(); } >>> >>> can be used for assignment: >>> >>> List list = Lists.newArrayList(); >>> >>> Although this construct can be used for assignment, it cannot be used >>> in parameter passing when a type argument is required: >>> >>> public void expectStringList(List list) { >>> ... >>> } >>> >>> expectStringList(Lists.newArrayList()); // doesn?t compile >>> expectStringList(Lists.newArrayList()); // does compile >>> >>> The fact that inference works for assignment but not for parameter >>> passing is very confusing and arbitrary. >>> Changing this would be consistent with the way type inference is >>> presented in this proposal. >>> >>> >> > From jeremy.manson at gmail.com Fri Feb 27 23:54:07 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Fri, 27 Feb 2009 23:54:07 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> Message-ID: <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> Hey Neal, I think you might have missed where I asked for an example where G1 and G2 might have different numbers of type parameters or they might have corresponding parameters in a different order. I'm probably missing a very obvious example, and I'm sure you have an example in mind. On Fri, Feb 27, 2009 at 11:33 PM, Neal Gafter wrote: > Adding conversions doesn't make type inference work. ?Each conversion > that you want to affect type inference has to be accommodated > specifically in the type inference algorithm. I wasn't suggesting that adding conversions would make type inference work. I was suggesting that the conversion could be done in place of the type inference. > I disagree with your suggestion that this should fail: > > ? ? List list = new ArrayList<>(); // should fail > > The equivalent code using static factories works just fine. ?It isn't > clear why this feature should behave differently, or what part of your > specification makes it fail. Basically, because I specifically disallowed wildcards under the sample spec. See the second bullet point under "Semantics and Compilation". However, I wasn't convinced that that was a good idea either, which is why I put it under Additional Features (at the end). The described technique under that header would make this example work (probably -- I'd have to double-check the JLS). > I don't think supporting casts adds value to the feature. ?You can > already assign, for example, from ArrayList to List without a > cast. That was where Josh was leaning when I asked him about it, too. The reason I thought it made sense was just for consistency's sake; basically, it is the only one of the five conversion contexts where this technique might work, but it doesn't. For assignments and method parameters, it will work, and for String and numeric conversions, it doesn't make any sense. Casting was the only one left. > > If you want to hear about the approach that Joe is working on, I'll be > happy to describe it in person at your convenience (with Joe, if he > wants). > I would definitely like to hear about it! How close is Joe to finishing a draft? Jeremy > On Fri, Feb 27, 2009 at 10:56 PM, Jeremy Manson wrote: >> Neal, >> >> I thought you had disappeared into the wilderness! ?I might not have >> written this if I thought that you were on the job. >> >> Anyway, it sounds as if you have an example in mind where G1 and G2 >> can have different type parameters. ?I have to say that the only ones >> that come to mind are the wildcard examples I give at the end of the >> proposal (where you have to infer the type's LUB). ?I was only going >> to pursue that if people thought it was a good idea. ?I imagine you >> have some others in mind? >> >> I did look at making modifications to the type inference algorithm, >> but I thought I could get away without it if you basically treat the >> entire operation as a conversion. ?It makes the proposal simpler not >> to have to tackle that particular issue. ?It seems less likely that >> this would be possible if G1 and G2 have to be able to have different >> type parameters. >> >> What do you think of the idea in the proposal for using this for >> casts? ?Do you think it makes sense to be able to say: >> >> List list = (List<>) new ArrayList(); >> >> Jeremy >> >> On Fri, Feb 27, 2009 at 10:28 PM, Neal Gafter wrote: >>> Jeremy- >>> >>> Where your spec says "the type parameters of G1 in the conversion >>> context are deemed to be identical to those of type G2" seems to >>> assume that the types G1 and G2 are related in a way that their type >>> parameters align exactly. ?That is not the case in general. ?G1 and G2 >>> might have different numbers of type parameters or they might have >>> "corresponding" parameters in a different order. >>> >>> The most significant problem with this proposal is that it completely >>> ignores the most difficult aspect of this feature - the required >>> modifications to the type inference algorithm specified in the JLS >>> (15.12.2.7 and 15.12.2.8). ?Joe Darcy and I discussed how to specify >>> that on Friday, and I believe he is preparing a proposal. >>> >>> Regards, >>> Neal >>> >>> On Fri, Feb 27, 2009 at 10:10 PM, Jeremy Manson wrote: >>>> Improved Type Inference for Generic Instance Creation >>>> >>>> (Sorry about the length; I probably got a little carried away) >>>> >>>> Author: Jeremy Manson >>>> >>>> Overview >>>> >>>> Feature Summary >>>> >>>> This proposal addresses the addition of limited type inference for >>>> class instance creation expressions to the Java programming language. >>>> In cases where parametrized types need to be explicitly declared for a >>>> constructor, and the full parametrized type < T1 , T2 , ...Tn > of >>>> that constructor is obvious from the context, then the ?parameterized >>>> type of the constructor can be replaced with an empty set of type >>>> parameters: <>. The <> ?construct is legal to use when constructing an >>>> ob ject and either assigning it to a variable, or when passing ?it as >>>> a parameter. >>>> >>>> For example, consider the following assignment statement: >>>> >>>> Map> anagrams = new HashMap>(); >>>> >>>> This is rather lengthy, so it can be replaced with this: >>>> >>>> Map> anagrams = new HashMap<>(); >>>> >>>> Major Advantages >>>> Generics have had a tremendously positive impact on type safety in the >>>> Java programming language. They ?have made it possible to provide >>>> static guarantees about the type of instances used by other classes, >>>> preventing entire classes of runtime errors from occurring. However, >>>> generics have added complexity to Java, making the code far more >>>> verbose and occasionally di?cult to read. Although solving this >>>> problem is well outside the scope of this proposal, a limited form of >>>> type inference would remove unnecessary redundancy from the language. >>>> >>>> The requirement that type parameters be duplicated unnecessarily like >>>> this encourages an unfortunate >>>> overabundance of static factory methods, simply because type inference >>>> works on method invocations. For >>>> example, the Google collections library [2] contains a class that >>>> wraps every possible constructor of every >>>> subclass of java.util.List in the JDK: >>>> >>>> public class Lists { >>>> ?public static List newArrayList() { return new ArrayList(); } >>>> ?public static List newArrayList(int i) { return new ArrayList(i); } >>>> ?// ... >>>> } >>>> List list = Lists.newArrayList(); >>>> >>>> This approach avoids the redundancy in the declaration, but requires >>>> two declarations for every possible >>>> constructor in every possible class. This is ugly: every time a >>>> constructor or a new subtype of List is created, >>>> this class must be updated. Furthermore, the names of these methods >>>> does not have to be consistent; there >>>> is no reason to favor newArrayList over createArrayList. The proposed >>>> feature would make this approach >>>> obsolete. >>>> >>>> Major Disadvantages >>>> >>>> As a minor change, the impact of this feature would have few >>>> disadvantages. It does have bene?ts and >>>> drawbacks when compared with other implementations, though. For >>>> example, it could be argued that >>>> inference would look cleaner without the <> token: >>>> >>>> Map> list = new Map(); >>>> >>>> Unfortunately, for the purposes of backwards compatibility, new Map() >>>> indicates a raw type, and therefore >>>> cannot be used for type inference. >>>> >>>> An argument can also be made for more full type inference: >>>> >>>> auto map = new HashMap(); >>>> map.get("Foo"); // map is understood to be a Map >>>> >>>> or, alternatively, for a typedef like feature, where type identi?ers >>>> are assigned to longer typenames: >>>> >>>> typedef MyMap HashMap>; >>>> MyMap m = new MyMap(); >>>> >>>> Both of these approaches, which are present in the forthcoming C++ >>>> standard, would eliminate a lot of >>>> verbosity, at the expense of (potentially) obscuring the type of the >>>> variable. Neither of these proposals are >>>> precluded by this proposal; one, both or neither can be done at a later date. >>>> >>>> 2 Examples >>>> >>>> Here is a simple example, showing a use case for type inference for >>>> blank ?nals. An ImmutableMap is a Map >>>> implementation that throws an exception when mutation is attempted. In >>>> this example, the programmer >>>> writes > twice instead of four times, and >>>> once instead of twice: >>>> >>>> class AllAnagrams { >>>> ?final Map> anagrams; >>>> ?AllAnagrams(List originals) { >>>> ? ?Map> map = new HashMap<>(); // saves typing >>>> ? ?for (String s : originals) { >>>> ? ? ?String alphagram = alphagram(word); >>>> ? ? ?List group = anagrams.get(alphagram); >>>> ? ? ?if (group == null) >>>> ? ? ? ?anagrams.put(alphagram, group = new ArrayList<>()); // saves typing >>>> ? ? ?group.add(word); >>>> ? ?} >>>> ? anagrams = new ImmutableMap<>(map); // saves typing >>>> ?} >>>> ?private static String alphagram(String s) { >>>> ? ?char[] chars = s.toCharArray(); >>>> ? ?Arrays.sort(chars); >>>> ? ?return String.valueOf(chars); >>>> ?} >>>> } >>>> >>>> Here is another example, showing a use case for type inference in >>>> parameter passing: >>>> class TreeNode { >>>> ?T value; >>>> ?TreeNode left, right; >>>> ?private List> buildPathsInternal( >>>> ? ?List> list, List currPath, TreeNode node) { >>>> ? ?if (node == null) { >>>> ? ? ?// type inference does not save typing here; see section on Wildcards. >>>> ? ? ?list.add(new ArrayList(currPath)); >>>> ? ? ?return list; >>>> ? ?} >>>> ? ?currPath.add(node); >>>> ? ?buildPathsInternal(list, currPath, node.left); >>>> ? ?buildPathsInternal(list, currPath, node.right); >>>> ? ?currPath.remove(node); >>>> ? ?return list; >>>> ?} >>>> ?public List> getAllPaths(TreeNode head) { >>>> ? ?// Type inference saves typing here: >>>> ? ?return buildPathsInternal(new ArrayList<>(), new LinkedList<>(), head); >>>> ?} >>>> } >>>> >>>> Details >>>> >>>> Speci?cation >>>> Informally, the speci?cation adds syntax to replace the type arguments >>>> < T1 ...Tn > to a class being instanti- >>>> ated by a call to new with the simple token <>. It also provides a new >>>> conversion that infers what the type >>>> arguments would have been from the context, and treats the instance >>>> creation as if those type arguments >>>> were present. >>>> >>>> Syntax >>>> The syntax of the new statement is currently given in two di?erent >>>> ways in the Java Language Speci?cation >>>> (JLS) [1] ?15.9 and JLS?18.1 For simplicity, we restrict ourselves to >>>> the grammar given in ?15.9. >>>> >>>> ClassInstanceCreationExpression ::= >>>> ?new TypeArguments_opt ClassOrInterfaceCreationType ( >>>> ArgumentList_opt ) ClassBody_opt >>>> ?Primary . new TypeArguments_opt Identifier >>>> PossiblyInferredTypeArguments ( ArgumentList_opt ) ClassBodyopt >>>> >>>> ClassOrInterfaceCreationType ::= >>>> ?TypeDeclSpecifier PossiblyInferredTypeArguments_opt >>>> >>>> PossiblyInferredTypeArguments ::= >>>> ?<> >>>> ?TypeArguments_opt >>>> >>>> Semantics and Compilation >>>> Consider G1 , a generic type that is declared with 0 type arguments, and G2 >>>> ?T1 , T2 , ..., Tn ?, a generic type >>>> that is declared with n type arguments. There is a Type Inference >>>> Conversion from G1 to G2 if and only if >>>> ?? G2 ?s erased type is a supertype of G1 ?s erased type and >>>> ?? all type arguments T1 , T2 ...Tn uniquely identify reference types >>>> (i.e., they have no wildcard type arguments, although see below for >>>> more discussion of this). >>>> >>>> A Type Inference Conversion can take place in an assignment or method >>>> invocation conversion context >>>> (JLS ?5). It might be possible to allow the inference to take place in >>>> a casting conversion context; see >>>> Section 6.1 for more discussion of this. >>>> >>>> Type Inference Conversions are unique in that they are not actually >>>> performed. Instead, they are used >>>> to replace the type they would ordinarily be converting: if a Type >>>> Inference Conversion can take place, then >>>> the type parameters of G1 in the conversion context are deemed to be >>>> identical to those of type G2 . >>>> >>>> Compilation >>>> The resulting bytecode would be identical to bytecode generated by the >>>> same code with the types inferred. >>>> >>>> Testing >>>> The proposed construct can be tested by writing a number of statements >>>> that construct instances using >>>> inferred types. These instances can then be assigned to variables and >>>> ?elds of speci?c types, and passed to >>>> methods that expect speci?c types. These tests should compile and run >>>> as expected: >>>> Set set = new SortedSet<>(); >>>> set.add("A"); >>>> set.add("B"); >>>> set.add("C"); >>>> // verify that set contains "A", "B", "C". >>>> >>>> Other tests can be performed by attempted to place new instances of >>>> inferred types in contexts that >>>> contain wildcards; these tests should fail: >>>> >>>> List list = new ArrayList<>(); // should fail >>>> List list = new ArrayList<>(); >>>> list.add("A"); >>>> list.addAll(new ArrayList<>()); // should fail, since addAll expects >>>> ? ?// Collection >>>> >>>> Library Support >>>> No library support is required, although libraries can be rewritten to >>>> take advantage of the new feature. >>>> >>>> Re?ective APIs >>>> No re?ective APIs need to be changed. The only related API is >>>> Class.newInstance; however, because >>>> generics are not rei?ed in Java, this API does not take type >>>> parameters. A compiler cannot infer non- >>>> existent type parameters. >>>> >>>> Other Changes >>>> No other parts of the platform need to be updated. >>>> >>>> Migration >>>> Libraries can be rewritten to take advantage of this feature, but it >>>> is not imperative that they do so. >>>> >>>> Compatibility >>>> This change is backwards compatible. It will not make any changes to >>>> break existing compilation strategies >>>> or existing code. >>>> >>>> References >>>> Existing Bugs: 4879776, 6242254, 5092426, 6220689, 4983159, 6368076 >>>> >>>> [1] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java >>>> Language Speci?cation, 3rd Edition. >>>> Addison Wesley, 2004. >>>> [2] Google Inc. Google Collections Classes. >>>> >>>> Additional Features >>>> >>>> Casting Conversion >>>> It would be possible to specify Type Inference Conversion so that it >>>> takes place in a Cast Context: >>>> >>>> List emptyList() { >>>> ?return (List) new ArrayList<>(); >>>> } >>>> This would keep the casting context consistent with the other >>>> conversion contexts. However, the utility of >>>> this is questionable, so an argument could be made that this is a >>>> needless change. >>>> >>>> Wildcards >>>> >>>> In the method buildPathsInternal in Section 2, we need to use >>>> ArrayList?s copy constructor to create a copy of a List, but >>>> cannot: >>>> >>>> if (node == null) { >>>> ?list.add(new ArrayList(currPath)); >>>> ?return list; >>>> } >>>> >>>> The inference does not work here because the ArrayList constructor >>>> expects an argument of type Collection>>> extends E>. The approach to inference described above needs to be able >>>> to determine the exact type of >>>> the type parameters being inferred. Since we don?t have an exact type >>>> here, the inference will fail. >>>> One possible tweak to our approach would be the ability to infer an >>>> actual type parameter from a >>>> wildcard. For example, if the least upper bound of a wildcard >>>> expression, when evaluated, would be a legal >>>> type parameter for the type being instantiated, we might consider >>>> inferring that type. This would make it >>>> possible to use type inference in the example above: >>>> >>>> if (node == null) { >>>> ?// > is inferred from Collection >>>> ?list.add(new ArrayList<>(currPath)); >>>> ?return list; >>>> } >>>> >>>> Further inference for method parameters >>>> As pointed out above, the result of a generic method: >>>> >>>> public static List newArrayList() { return new ArrayList(); } >>>> >>>> can be used for assignment: >>>> >>>> List list = Lists.newArrayList(); >>>> >>>> Although this construct can be used for assignment, it cannot be used >>>> in parameter passing when a type argument is required: >>>> >>>> public void expectStringList(List list) { >>>> ... >>>> } >>>> >>>> expectStringList(Lists.newArrayList()); // doesn?t compile >>>> expectStringList(Lists.newArrayList()); // does compile >>>> >>>> The fact that inference works for assignment but not for parameter >>>> passing is very confusing and arbitrary. >>>> Changing this would be consistent with the way type inference is >>>> presented in this proposal. >>>> >>>> >>> >> > From Joe.Darcy at Sun.COM Sat Feb 28 00:02:29 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Sat, 28 Feb 2009 00:02:29 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> Message-ID: <49A8EF95.4040306@sun.com> Jeremy Manson wrote: > Hey Neal, > > I think you might have missed where I asked for an example where G1 > and G2 might have different numbers of type parameters or they might > have corresponding parameters in a different order. I'm probably > missing a very obvious example, and I'm sure you have an example in > mind. > > On Fri, Feb 27, 2009 at 11:33 PM, Neal Gafter wrote: > >> Adding conversions doesn't make type inference work. Each conversion >> that you want to affect type inference has to be accommodated >> specifically in the type inference algorithm. >> > > I wasn't suggesting that adding conversions would make type inference > work. I was suggesting that the conversion could be done in place of > the type inference. > > >> I disagree with your suggestion that this should fail: >> >> List list = new ArrayList<>(); // should fail >> >> The equivalent code using static factories works just fine. It isn't >> clear why this feature should behave differently, or what part of your >> specification makes it fail. >> > > Basically, because I specifically disallowed wildcards under the > sample spec. See the second bullet point under "Semantics and > Compilation". However, I wasn't convinced that that was a good idea > either, which is why I put it under Additional Features (at the end). > The described technique under that header would make this example work > (probably -- I'd have to double-check the JLS). > > >> I don't think supporting casts adds value to the feature. You can >> already assign, for example, from ArrayList to List without a >> cast. >> > > That was where Josh was leaning when I asked him about it, too. The > reason I thought it made sense was just for consistency's sake; > basically, it is the only one of the five conversion contexts where > this technique might work, but it doesn't. For assignments and method > parameters, it will work, and for String and numeric conversions, it > doesn't make any sense. Casting was the only one left. > > >> If you want to hear about the approach that Joe is working on, I'll be >> happy to describe it in person at your convenience (with Joe, if he >> wants). >> >> > > I would definitely like to hear about it! How close is Joe to > finishing a draft? > Joe hasn't started a draft! Neal and I discussed some implementation strategies that could also guide a specification. I'll send out more in the next few days. Good night, -Joe From scolebourne at joda.org Sat Feb 28 04:07:58 2009 From: scolebourne at joda.org (Stephen Colebourne) Date: Sat, 28 Feb 2009 12:07:58 +0000 Subject: Proposal discussions, support and opposition? In-Reply-To: <15e8b9d20902272121q2f625b1cq3230f5260bcddfe4@mail.gmail.com> References: <15e8b9d20902272121q2f625b1cq3230f5260bcddfe4@mail.gmail.com> Message-ID: <49A9291E.6030706@joda.org> How is it intended that this list is intended to be used? It is just to submit proposals? Or for broader discussion about their applicability, style, fit with Java, future directions of Java, etc. And will there be any other means to express support or opposition to particular proposals other than via this mailing list? Stephen From jjb at google.com Sat Feb 28 04:34:03 2009 From: jjb at google.com (Joshua Bloch) Date: Sat, 28 Feb 2009 04:34:03 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> Message-ID: <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> Neal, On Fri, Feb 27, 2009 at 11:20 PM, Neal Gafter wrote: > The proposed changes to existing APIs introduce an incompatibility. > This, for example, is legal today: > > interface A extends java.sql.Connection, java.io.Closeable {} > > However, since you propose that Connection would extend > Disposable and Closable would extend > Disposable, interface A is broken after the proposed > change. Also, the changes you propose to existing APIs introduce > changes to overload resolution that can break existing code. While this is technically an incompatibility, I don't think it's likely to cause problems in practice. Look around and see if you can find any examples to the contrary; I am genuinely curious. Keep in mind that adding a method to any nonfinal type is technically incompatible in this way, and yet we do it each release. As long as it's done tastefully, it isn't a problem. > > You also missed a few disadvantages. > > o All of the difficult decisions that you defer to the expert group, > such as the handling of exceptions, suggest that this solution is > likely to be a poor match for many uses, resulting in the sort of > shoehorning of code into the construct that results in errors. Whoa! That is false, and mildly insulting. I did not "defer the difficult decisions to the expert group." The proposal says precisely how exceptions are to be handled: the first exceptions wins. This is what people would do today if weren't so difficult to code up. Since your premise (that I have deferred the hard decisions to the expert group) is wrong, your conclusion (that "the solution is likely to be a poor match for many uses, resulting in the sort of shoehorning of code into the construct that results in errors") is unwarranted. > > o This approach of adding point solutions one-by-one to a language for > particular use cases results in a general degradation of the quality > of the language over time with little lifting of the level of > abstraction, so any change of this sort should be viewed with great > skepticism. This is not a "point solution." It is a well established construct, much used and loved in other languages including C# (the using statement) and Python ( the with statement). C++ programmers use destructors to similar effect, and laud the resulting "RAII" pattern. > > o Given the short time frame that project coin is to complete its work > and the nature of this solution -- attempting to maximize the utility > in the most common use cases while minimizing the likelihood of user > error in using the construct -- it seems unlikely that we will not > have the time to experiment with all the variables in realistic > contexts. There are very few variables: this proposal is close to complete. It solves a simple, universal problem in a well-tested fashion. > Therefore, one should add to the disadvantages the very > real chance that the language construct is likely to get some of these > aspects wrong if added in the JDK7 timeframe. The fact that these > issues haven't been resolved in the 32+ months since you started > working on this proposal, or in the 13+ months since a prototype has > been available, suggests that 3-6 months is not a reasonable timeframe > to resolve them, and even hints that there may be no generally > acceptable solution. I'm not quite sure what issues you mean. A long while back (at OOPSLA 2004), I suggested that Java needed an automatic resource management statement, but I did not work on the details. Recently Joe Darcy announced a call for proposals in connection with project Coin, so I worked on the details. It was, as I suspected, a relatively simple matter to put together a solid proposal in a short period of time. Talk of "hints that there may be no generally acceptable solution" amounts to casting aspersions on the proposal without noting any real shortcomings. > > > You also forgot to mention the obvious alternatives. Most > prominently, control abstraction via closures (BGGA or JCA) allows API > designers to tune the behavior for the various use cases (APIs) > without the need for point-solution API-specific language changes. I don't see this proposal as being related to closures in any way. There are languages with both closures and resource management (C#), neither (C), automatic resource management only (C++), and closures only (Scheme). Whether or not Java gets something like BGGA or JCA in the future, automatic resource management would be an extremely valuable addition to the language in the next release. > > Generally, this proposal appears to leave too many open issues to be > suitable for inclusion in the coin project/JSR. But you haven't mentioned any! So far as I know, this proposal is comparable in its completeness to the other proposals that we've seen for Project Coin. Regards, Josh From neal at gafter.com Sat Feb 28 06:35:24 2009 From: neal at gafter.com (Neal Gafter) Date: Sat, 28 Feb 2009 06:35:24 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> Message-ID: <15e8b9d20902280635g642f47h334c593c542a3860@mail.gmail.com> On Fri, Feb 27, 2009 at 11:54 PM, Jeremy Manson wrote: > Hey Neal, > > I think you might have missed where I asked for an example where G1 > and G2 might have different numbers of type parameters or they might > have corresponding parameters in a different order. ?I'm probably > missing a very obvious example, and I'm sure you have an example in > mind. Sure. A very simple example would be interface A { ... } class B implements A { ... } Please don't let the use cases drive the design. Use cases are appropriate to test whether a design satisfies its requirements, but tuning the design to the use cases results in a writhing mass of special cases. I've written about this category of language-design error before , and the importance you seem to place on this question suggests that is the approach you're using. > On Fri, Feb 27, 2009 at 11:33 PM, Neal Gafter wrote: >> Adding conversions doesn't make type inference work. ?Each conversion >> that you want to affect type inference has to be accommodated >> specifically in the type inference algorithm. > > I wasn't suggesting that adding conversions would make type inference > work. ?I was suggesting that the conversion could be done in place of > the type inference. It can't if you want overload resolution to work. Overload resolution relies on type inference. You appear to be taking the approach of adding a new kind of type to represent the result of these new kinds of class creation expressions. To complete the work using this approach, you will need to provide some evidence (better yet, sketch a proof) that this approach is a sound extension of the type system. I strongly suspect it isn't sound. I think one can prove that it isn't sound by composing your new subtype rule with the natural subtype rule for intersection types in the context of an invocation of a generic method. From jeremy.manson at gmail.com Sat Feb 28 07:33:01 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sat, 28 Feb 2009 07:33:01 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <15e8b9d20902280635g642f47h334c593c542a3860@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> <15e8b9d20902280635g642f47h334c593c542a3860@mail.gmail.com> Message-ID: <1631da7d0902280733q2e1ab848qd6c4b6a48483d05b@mail.gmail.com> On Sat, Feb 28, 2009 at 6:35 AM, Neal Gafter wrote: > On Fri, Feb 27, 2009 at 11:54 PM, Jeremy Manson wrote: >> Hey Neal, >> >> I think you might have missed where I asked for an example where G1 >> and G2 might have different numbers of type parameters or they might >> have corresponding parameters in a different order. ?I'm probably >> missing a very obvious example, and I'm sure you have an example in >> mind. > > Sure. ?A very simple example would be > > interface A { ... } > class B implements A { ... } > > Please don't let the use cases drive the design. ?Use cases are > appropriate to test whether a design satisfies its requirements, but > tuning the design to the use cases results in a writhing mass of > special cases. ?I've written about this category of language-design > error before , > and the importance you seem to place on this question suggests that is > the approach you're using. I understand your concern about this, but I think that perhaps I was a little unclear about my goals. When I was writing this proposal, I was deliberately trying to make it limited in scope, but leave room for it to be expanded for future, more comprehensive type inference solutions (say, in Java 8 or later). My feeling was that it was okay if I missed some of the hard cases, as long as what I was doing covered more useful cases and left room for the harder ones to be included in a future JSR. That's also one of the reasons why I made inference for wildcards optional -- I thought that we might not have time to get it right. >> On Fri, Feb 27, 2009 at 11:33 PM, Neal Gafter wrote: >>> Adding conversions doesn't make type inference work. ?Each conversion >>> that you want to affect type inference has to be accommodated >>> specifically in the type inference algorithm. >> >> I wasn't suggesting that adding conversions would make type inference >> work. ?I was suggesting that the conversion could be done in place of >> the type inference. > > It can't if you want overload resolution to work. ?Overload resolution > relies on type inference. > > You appear to be taking the approach of adding a new kind of type to > represent the result of these new kinds of class creation expressions. > ?To complete the work using this approach, you will need to provide > some evidence (better yet, sketch a proof) that this approach is a > sound extension of the type system. ?I strongly suspect it isn't > sound. ?I think one can prove that it isn't sound by composing your > new subtype rule with the natural subtype rule for intersection types > in the context of an invocation of a generic method. > I was doing something a little dodgier than adding a type, and I admit to not having been sure that it would work. Basically, I was trying to add a conversion that doesn't actually convert, but instead changes the type of the from-expression. I will go and think about how / if this works with intersection types and generic method invocation. Jeremy From neal at gafter.com Sat Feb 28 07:41:11 2009 From: neal at gafter.com (Neal Gafter) Date: Sat, 28 Feb 2009 07:41:11 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> Message-ID: <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> Josh- The compatibility section must document incompatibilities, whether or not you judge them likely to cause problems in practice. To be complete at a level suitable for project coin, you should provide a specification of all of the semantics. For example, there is nothing comparable to JLS section 11.2.2, exception analysis, which for this construct is much more complex than the existing statements and therefore must be spelled out. Particularly concerning to me is the fact that this translation would sometimes silently swallow exceptions indicating serious program failures (this too should be listed among the disadvantages); completing the exception analysis specification would make that problem more obvious. What are the completion analysis rules? If the variable becomes null before the finally block, is NullPointerException thrown? What if the variable is assigned to some other value? Does this construct then close some other resource than the one opened? These questions should be clear from the spec, and for these questions the answer is either unclear or quite unlikely to be what you intend. The fact that you proposed two possible but semantically distinct translations suggests that not all is settled. In the C# world, the using statement has the "shoehorning" issue that I described. I can tell you from experience that it does encourage clients to implement the IDisposable interface, and a method named Dispose, to use the pattern, even though that may be very unnatural to the API. It is a flaw in the language that we're aware of and working to repair. From jeremy.manson at gmail.com Sat Feb 28 07:54:14 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sat, 28 Feb 2009 07:54:14 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <1631da7d0902280733q2e1ab848qd6c4b6a48483d05b@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> <15e8b9d20902280635g642f47h334c593c542a3860@mail.gmail.com> <1631da7d0902280733q2e1ab848qd6c4b6a48483d05b@mail.gmail.com> Message-ID: <1631da7d0902280754xd12446fkc97ae5b9700d418@mail.gmail.com> On Sat, Feb 28, 2009 at 7:33 AM, Jeremy Manson wrote: > On Sat, Feb 28, 2009 at 6:35 AM, Neal Gafter wrote: >> On Fri, Feb 27, 2009 at 11:54 PM, Jeremy Manson wrote: >>> Hey Neal, >>> >>> I think you might have missed where I asked for an example where G1 >>> and G2 might have different numbers of type parameters or they might >>> have corresponding parameters in a different order. ?I'm probably >>> missing a very obvious example, and I'm sure you have an example in >>> mind. >> >> Sure. ?A very simple example would be >> >> interface A { ... } >> class B implements A { ... } >> >> Please don't let the use cases drive the design. ?Use cases are >> appropriate to test whether a design satisfies its requirements, but >> tuning the design to the use cases results in a writhing mass of >> special cases. ?I've written about this category of language-design >> error before , >> and the importance you seem to place on this question suggests that is >> the approach you're using. > > I understand your concern about this, but I think that perhaps I was a > little unclear about my goals. When I was writing this proposal, I was > deliberately trying to make it limited in scope, but leave room for it > to be expanded for future, more comprehensive type inference solutions > (say, in Java 8 or later). ?My feeling was that it was okay if I > missed some of the hard cases, as long as what I was doing covered > more useful cases and left room for the harder ones to be included in > a future JSR. ?That's also one of the reasons why I made inference for > wildcards optional -- I thought that we might not have time to get it > right. > Also, with regard to changing type parameter number / positions specifically, I didn't really understand the motivation for them until you gave me the example. You need *some* motivation before including a feature. Now I understand what you mean, although I'm not 100% convinced that it needs to be included in this proposal (for the reason above, as well as still needing to think about it before I am completely convinced it is a good idea). Jeremy From neal at gafter.com Sat Feb 28 09:03:09 2009 From: neal at gafter.com (Neal Gafter) Date: Sat, 28 Feb 2009 09:03:09 -0800 Subject: Proposal: Improved Wildcard Syntax for Java Message-ID: <15e8b9d20902280903h32967535l8f6e4f6580fdd93d@mail.gmail.com> Improved Wildcard Syntax for Java http://docs.google.com/Doc?id=ddb3zt39_79g2mtpccz AUTHOR(S): Neal Gafter OVERVIEW The current syntax for Java's wildcards is confusing enough that mneumonics are required to read code.? We suggest adding an alternative syntax that is much more readable, and then migrating code to the more readable syntax over time. FEATURE SUMMARY: [Note: since this is an additional syntax for a feature already in the language, most existing tutorial material can be used.] A covariant wildcard generic argument can be written either "? extends Y" or "out Y". A contravariant wildcard generic argument can be written either "? super Y" or "in Y". MAJOR ADVANTAGE: While the existing syntax is mneumonic from the point of view of describing its effect on the type system, it is not mneumonic in its use.? The new syntax is self-mneumonic for users. MAJOR BENEFIT: Jave code that uses wildcards is more readable, as are diagnostics involving them. MAJOR DISADVANTAGE: Two ways of doing the same thing, though we hope code will migrate over time toward the new more readable syntax. ALTERNATIVES: None. EXAMPLES SIMPLE EXAMPLE: interface Collection { ??? boolean addAll(Collection c); ??? ... } ADVANCED EXAMPLE: class Collections { ??? public static > void sort(List list) {...} ??? public static void sort(List list, Comparator c) {...} ??? int binarySearch(List> list, T key) {...} ??? public static void fill(List list, T obj) {...} ??? public static void copy(List dest, List src) { ??? ... } DETAILS SPECIFICATION: "in" and "out" are added as context-sensitive keywords with precisely the same meaning of "? super" and "? extends".? As context-sensitive keywords, they continue to be usable as identifiers in all contexts. COMPILATION: As today. TESTING: As today, though a bit of additional work to ensure that the context sensitive keyword is handled properly by the compiler.? Specifically, that they continue to be fully usable as identifiers in other contexts. LIBRARY SUPPORT: None. REFLECTIVE APIS: None. OTHER CHANGES: None. MIGRATION: A trivial textual substitution can be used to translate old code to the new syntax. COMPATIBILITY BREAKING CHANGES: None. EXISTING PROGRAMS: No impact. REFERENCES EXISTING BUGS: None URL FOR PROTOTYPE (optional): None From Joe.Darcy at Sun.COM Sat Feb 28 10:00:53 2009 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Sat, 28 Feb 2009 10:00:53 -0800 Subject: Proposal discussions, support and opposition? In-Reply-To: <49A9291E.6030706@joda.org> References: <15e8b9d20902272121q2f625b1cq3230f5260bcddfe4@mail.gmail.com> <49A9291E.6030706@joda.org> Message-ID: <49A97BD5.6050104@sun.com> Stephen Colebourne wrote: > How is it intended that this list is intended to be used? > > It is just to submit proposals? > > Or for broader discussion about their applicability, style, fit with > Java, future directions of Java, etc. > Yes, the list is for analysis, refinement, and discussion of the proposals as well. > And will there be any other means to express support or opposition to > particular proposals other than via this mailing list? > > I'm sure people will register their support or opposition for proposals in many other forums! However, I think the list should serve as the central location for the discussion to occur. -Joe From jjb at google.com Sat Feb 28 11:08:04 2009 From: jjb at google.com (Joshua Bloch) Date: Sat, 28 Feb 2009 11:08:04 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> Message-ID: <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> Neal, On Sat, Feb 28, 2009 at 7:41 AM, Neal Gafter wrote: > Josh- > > The compatibility section must document incompatibilities, whether or > not you judge them likely to cause problems in practice. Good point. I will add this one. And I am still interested in whether anyone can find some code in an existing codebase that tickles this. > > > To be complete at a level suitable for project coin, you should > provide a specification of all of the semantics. For example, there > is nothing comparable to JLS section 11.2.2, exception analysis, which > for this construct is much more complex than the existing statements > and therefore must be spelled out. I have done so in the "Semantics and Compilation" section: it's implicit in the desugaring. The project lead (Joe Darcy) said this in a personal communication: "I suppose the desugarings should cover issues related to flow analysis with the new statement form." Of course we can translate the desugaring into JLS-ready prose when the time comes, but I don't think it would aid in understanding the proposal. Particularly concerning to me is > the fact that this translation would sometimes silently swallow > exceptions indicating serious program failures Unless I am missing something, the construct only "silently swallows" exceptions when they are intentionally suppressed in favor of prior exceptions, which typically indicate more serious problems. I did describe, in the "Additional Features" section, a facility whereby suppressed exceptions are associated with the exception for which they were suppressed: Here are several features that might be added to the construct if the expert group deemed it advisable: Retaining suppressed exceptions - As described above, the construct simply discards exceptions that are suppressed. It would probably be better to attach them to the exception in whose favor they are being suppressed. This would entail adding two new methods to Throwable, void addSuppressedException(Throwable) and Throwable[] getSuppressedExceptions(). I do think this is worth doing, and I will "promote it" to the body of the proposal if that is the consensus. If the variable becomes null before the > finally block, is NullPointerException thrown? As per the desugaring, the resource variable is implicitly final. In any practical use, you'll get an NPE in the explicit block, but yes, if you construct an artificial example where the resource is not actually used, you'll get a NullPointerException in the (implicit) close, again as per the desugaring. > What if the variable > is assigned to some other value? It won't compile, as the variable is implicitly final. My guess is that you had a hard time reading the desugaring due to the lack of formatting. I'll send you the pdf:) > Does this construct then close some > other resource than the one opened? Sorry, but I don't understand this question. Again, I suspect the desugaring will make this clear. > These questions should be clear > from the spec, and for these questions the answer is either unclear or > quite unlikely to be what you intend. I don't think this is true. In each case you've mentioned, the behavior was intentional and is clearly specified by the desugaring. I believe that it would be straightforward to translate the desugaring into JLS-style prose, but I don't think it would improve the proposal. As the proposal says, my intent was to "emphasizes brevity and clarity." > The fact that you proposed two > possible but semantically distinct translations suggests that not all > is settled. Sorry for the confusion. I did this for pedagogical reasons. The first translation was meant to quickly explain the construct. The second was meant to add a desirable feature, and should be regarded as correct. I could remove the first one from the proposal and go straight to the second, but I'm afraid the resulting proposal would be harder to understand. I will add prose to clarify that the second desugaring supersedes the first. > > > In the C# world, the using statement has the "shoehorning" issue that > I described. I can tell you from experience that it does encourage > clients to implement the IDisposable interface, and a method named > Dispose, to use the pattern, even though that may be very unnatural to > the API. It is a flaw in the language that we're aware of and working > to repair. I have little experience with C# so I'll have to defer to you on issues concerning this language. But in Python, I am led to understand that the with statement is very well liked. The same goes for the the RAII pattern in C++. The need for automatic resource management in Java is made abundantly clear by the fact that 2/3 of the uses of the close method in the JDK are wrong. I myself got it wrong (twice) in java.util.prefs. And our solution on page 88 of Java Puzzlers is also wrong: it silently swallows the exception when closing a file that was open for write. Josh From neal at gafter.com Sat Feb 28 11:27:19 2009 From: neal at gafter.com (Neal Gafter) Date: Sat, 28 Feb 2009 11:27:19 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> Message-ID: <15e8b9d20902281127w4c547139h8c517363525c085f@mail.gmail.com> On Sat, Feb 28, 2009 at 11:08 AM, Joshua Bloch wrote: >> ?Particularly concerning to me is >> the fact that this translation would sometimes silently swallow >> exceptions indicating serious program failures > > Unless I am missing something, the construct only "silently swallows" > exceptions when?they are intentionally suppressed in favor of prior > exceptions, which typically indicate more serious problems. The language construct as you specified it has no way to determine which exception is more serious. For example, a VM failure, such as an out-of-memory condition on the close(), is more serious than a closed connection on a particular write. The "solution" you proposed for this is unlikely to help. I understand that this was intentional on your part, but it is still a serious problem with the proposal that should be called out. From jjb at google.com Sat Feb 28 12:33:03 2009 From: jjb at google.com (Joshua Bloch) Date: Sat, 28 Feb 2009 12:33:03 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <15e8b9d20902281127w4c547139h8c517363525c085f@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> <15e8b9d20902281127w4c547139h8c517363525c085f@mail.gmail.com> Message-ID: <17b2302a0902281233w5cb6da96sd0227e27426fbf45@mail.gmail.com> Neal, On Sat, Feb 28, 2009 at 11:27 AM, Neal Gafter wrote: > On Sat, Feb 28, 2009 at 11:08 AM, Joshua Bloch wrote: > >> Particularly concerning to me is > >> the fact that this translation would sometimes silently swallow > >> exceptions indicating serious program failures > > > > Unless I am missing something, the construct only "silently swallows" > > exceptions when they are intentionally suppressed in favor of prior > > exceptions, which typically indicate more serious problems. > > The language construct as you specified it has no way to determine > which exception is more serious. For example, a VM failure, such as > an out-of-memory condition on the close(), is more serious than a > closed connection on a particular write. Please take a closer look at the desugaring! Like all VM failures, OutOfMemoryError is not a subtype of Exception, so it will never be suppressed by the automatic resource management statement. This is by design. While the specified suppression behavior may not be perfect, it does a far better job than most programmers do when left to cope with the situation themselves. Josh From neal at gafter.com Sat Feb 28 13:04:44 2009 From: neal at gafter.com (Neal Gafter) Date: Sat, 28 Feb 2009 13:04:44 -0800 Subject: Proposal: Automatic Resource Management In-Reply-To: <17b2302a0902281233w5cb6da96sd0227e27426fbf45@mail.gmail.com> References: <17b2302a0902272128x4bb817ffmd2058f1174a9058b@mail.gmail.com> <15e8b9d20902272143y95d742brdf47cc72c49a3919@mail.gmail.com> <17b2302a0902272229ycc7bf2dx36e03429aa629e05@mail.gmail.com> <15e8b9d20902272320g795546a6ya8acfe85b53dedad@mail.gmail.com> <17b2302a0902280434l4c402408ga05f8a5c1bfe0c2a@mail.gmail.com> <15e8b9d20902280741q17b33d86lf323f62d2759df3@mail.gmail.com> <17b2302a0902281108l64f2a7t3bd109a9941c6751@mail.gmail.com> <15e8b9d20902281127w4c547139h8c517363525c085f@mail.gmail.com> <17b2302a0902281233w5cb6da96sd0227e27426fbf45@mail.gmail.com> Message-ID: <15e8b9d20902281304h7ce74ec3ua07f3b363e85cb11@mail.gmail.com> On Sat, Feb 28, 2009 at 12:33 PM, Joshua Bloch wrote: >> The language construct as you specified it has no way to determine >> which exception is more serious. ?For example, a VM failure, such as >> an out-of-memory condition on the close(), is more serious than a >> closed connection on a particular write. > > Please take a closer look at the desugaring! Like all VM > failures,?OutOfMemoryError is not a subtype of Exception, so it will never > be suppressed by the automatic resource management statement. ?This is by > design. ?While the specified suppression behavior may not be perfect, it > does a far better job than most programmers do when left to cope with the > situation themselves. My point remains, even if not with this particular exception. From jeremy.manson at gmail.com Sat Feb 28 16:04:02 2009 From: jeremy.manson at gmail.com (Jeremy Manson) Date: Sat, 28 Feb 2009 16:04:02 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <15e8b9d20902280635g642f47h334c593c542a3860@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> <15e8b9d20902280635g642f47h334c593c542a3860@mail.gmail.com> Message-ID: <1631da7d0902281604w43ae8439t74b778aafdb5371a@mail.gmail.com> On Sat, Feb 28, 2009 at 6:35 AM, Neal Gafter wrote: > On Fri, Feb 27, 2009 at 11:54 PM, Jeremy Manson wrote: >> On Fri, Feb 27, 2009 at 11:33 PM, Neal Gafter wrote: >>> Adding conversions doesn't make type inference work. Each conversion >>> that you want to affect type inference has to be accommodated >>> specifically in the type inference algorithm. >> >> I wasn't suggesting that adding conversions would make type inference >> work. I was suggesting that the conversion could be done in place of >> the type inference. > > It can't if you want overload resolution to work. ?Overload resolution > relies on type inference. > > You appear to be taking the approach of adding a new kind of type to > represent the result of these new kinds of class creation expressions. > ?To complete the work using this approach, you will need to provide > some evidence (better yet, sketch a proof) that this approach is a > sound extension of the type system. ?I strongly suspect it isn't > sound. ?I think one can prove that it isn't sound by composing your > new subtype rule with the natural subtype rule for intersection types > in the context of an invocation of a generic method. > I've thought about this some more (after a nap :) ). My current position is that I'm not actually introducing a new kind of type. What I am introducing is a hole where a type goes later (when it can be inferred). This needs to be clearer in the proposal (where, on rereading, it does imply I am introducing a type). Given that, I don't think it interferes with the subtype rule for intersection types. You basically apply the inference / rules for overload resolution under the assumption that the type of the actual parameter is an erased type (which does not introduce any constraints, I believe), and then you "drop in" the type arguments to the formal parameter as the type arguments to the actual. It is reasonably clear to me that my aims were more modest than yours. Some of the things you want to do (like change parameter order) cannot be done without deeper type hackery. I would be interested in pursuing that if we decide that that is what we want as a group, so we should probably have a higher-level discussion about what our goals for this proposal are. Jeremy From neal at gafter.com Sat Feb 28 21:06:04 2009 From: neal at gafter.com (Neal Gafter) Date: Sat, 28 Feb 2009 21:06:04 -0800 Subject: Proposal: Improved Type Inference for Generic Instance Creation In-Reply-To: <1631da7d0902281604w43ae8439t74b778aafdb5371a@mail.gmail.com> References: <1631da7d0902272210i3f7b4873s71ba39d1eb26f4d1@mail.gmail.com> <15e8b9d20902272228g3bc33a95g587ea671e5641570@mail.gmail.com> <1631da7d0902272256o3fef0b28k65b619042b113fb8@mail.gmail.com> <15e8b9d20902272333n4c288ae5o2f9ddd71ad4db93d@mail.gmail.com> <1631da7d0902272354v7e983a3dufe360ea81e9757cf@mail.gmail.com> <15e8b9d20902280635g642f47h334c593c542a3860@mail.gmail.com> <1631da7d0902281604w43ae8439t74b778aafdb5371a@mail.gmail.com> Message-ID: <15e8b9d20902282106v35d00738k257687703dc80d5a@mail.gmail.com> On Sat, Feb 28, 2009 at 4:04 PM, Jeremy Manson wrote: > I've thought about this some more (after a nap :) ). ?My current > position is that I'm not actually introducing a new kind of type. > What I am introducing is a hole where a type goes later (when it can > be inferred). ?This needs to be clearer in the proposal (where, on > rereading, it does imply I am introducing a type). ?Given that, I > don't think it interferes with the subtype rule for intersection > types. ?You basically apply the inference / rules for overload > resolution under the assumption that the type of the actual parameter > is an erased type (which does not introduce any constraints, I > believe), and then you "drop in" the type arguments to the formal > parameter as the type arguments to the actual. > > It is reasonably clear to me that my aims were more modest than yours. > ?Some of the things you want to do (like change parameter order) > cannot be done without deeper type hackery. ?I would be interested in > pursuing that if we decide that that is what we want as a group, so we > should probably have a higher-level discussion about what our goals > for this proposal are. Jeremy- If you intend to constrain the relationship between G1 and G2 by the way their type parameters are related, you should add that to the specification. The way you describe your intent in the specification, it seems as if you're saying that the type "changes" when the conversion is applied. That is unlike anything else in the language. The JLS currently assigns a single type to every expression in the language, statically. Two types are either related by a subtype relationship, or they aren't, and the result shouldn't depend on the order by which subtype tests are done. Dropping an erased type into type inference may "break" type inference. For example, it may result in erased types in the results of type inference. Given the delicacy of type inference, these things either need to be worked out in detail more formally, of the specification should be based entirely on existing mechanisms. Joe and I have been looking at the latter approach. I'll be surprised if Joe includes in project Coin any proposals that have substantial outstanding technical issues. Regards, Neal From reinier at zwitserloot.com Sat Feb 28 23:08:41 2009 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Sun, 1 Mar 2009 08:08:41 +0100 Subject: Proposal: Improved Wildcard Syntax for Java Message-ID: <1FFA42B7-B682-4FD0-A39E-BD9C04207085@zwitserloot.com> This proposal is lacking in the 'disadvantages' section, in two ways. The listed disadvantage is unfairly sugared over; because the 'out/in' terminology does not allow you to bind the generics parameter, the 'extends'/'super' syntax will never become outdated and the need to remember that 'out' is analogous to 'extends' and 'in' is analogous to 'super' does not go away. There's another disadvantage that isn't listed at all: Neither 'in' nor 'out' are keywords in java currently. Therefore, you introduce the notion of a context-sensitive keyword, but as far as I understand it, java does not currently have context-sensitive keywords. Adding them is a big can of worms that should probably warrant some discussion (in the sense that it may complicate java parsers, and how the idea of context-sensitive keywords makes it a lot harder for any parser to use a keyword as an anchor point); at any rate it is a disadvantage that should be listed. There's also a typo in 'mneumonic' :) NB: For what it's worth, because the need to remember super-produces extends-consumes does not go away, I don't think this is going to help much. Perhaps make 'out' and 'in' valid context-sensitive keywords that can be used as a substitution for super and extends, and add that a missing generics variable on the LHS implies a wildcard? --Reinier Zwitserloot From neal at gafter.com Sat Feb 28 23:28:08 2009 From: neal at gafter.com (Neal Gafter) Date: Sat, 28 Feb 2009 23:28:08 -0800 Subject: Proposal: Improved Wildcard Syntax for Java In-Reply-To: <1FFA42B7-B682-4FD0-A39E-BD9C04207085@zwitserloot.com> References: <1FFA42B7-B682-4FD0-A39E-BD9C04207085@zwitserloot.com> Message-ID: <15e8b9d20902282328v66a000e4ub1613d9811b86642@mail.gmail.com> On Sat, Feb 28, 2009 at 11:08 PM, Reinier Zwitserloot wrote: > This proposal is lacking in the 'disadvantages' section, in two ways. > > The listed disadvantage is unfairly sugared over; because the 'out/in' > terminology does not allow you to bind the generics parameter, the > 'extends'/'super' syntax will never become outdated and the need to > remember that 'out' is analogous to 'extends' and 'in' is analogous to > 'super' does not go away. I don't understand. out/in bind the generic parameter in precisely the same way that ?extends and ?super do. What you describe is a disadvantage of the current syntax, but when using the new syntax you don't have to remember it, because the new syntax is self-mneumonic. > There's another disadvantage that isn't listed at all: Neither 'in' > nor 'out' are keywords in java currently. Therefore, you introduce the > notion of a context-sensitive keyword, but as far as I understand it, > java does not currently have context-sensitive keywords. Adding them > is a big can of worms that should probably warrant some discussion (in > the sense that it may complicate java parsers, and how the idea of > context-sensitive keywords makes it a lot harder for any parser to use > a keyword as an anchor point); at any rate it is a disadvantage that > should be listed. Any change in syntax has to be considered for its interaction with other tools, but for this particular case the general concerns you express don't seem to be an issue. For example, this syntax is very easy to parse with no more than the usual one-token lookahead. > There's also a typo in 'mneumonic' :) > > NB: For what it's worth, because the need to remember super-produces > extends-consumes does not go away, I don't think this is going to help > much. You don't have to remember that when reading and writing the new syntax. > Perhaps make 'out' and 'in' valid context-sensitive keywords > that can be used as a substitution for super and extends That's exactly what we've done, but with in/out you don't use the question mark either. > and add that > a missing generics variable on the LHS implies a wildcard? I don't understand what you propose, or see how it relates to this proposal. From rssh at gradsoft.com.ua Sat Feb 28 19:46:05 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Sun, 1 Mar 2009 05:46:05 +0200 (EET) Subject: PROPOSAL: Multiline strings Message-ID: AUTHOR(s): Ruslan Shevchenko OVERVIEW: FEATURE SUMMARY: add multiline strings to java language. MAJOR ADVANTAGE: Possibility more elegant to write code part of codes in other languages, such as sql constructions or rendering of html components. MAJOR DISADVANTAGE I don't know ALTERNATIVES: use String "+=" operator. using groovy instead java in utility classes. EXAMPLES SIMPLE EXAMPLE: StringBuilder sb = new StringBuilder(); sb.append("""select a from Area a, CountryCodes cc where cc.isoCode='UA' and a.owner = cc.country """); if (question.getAreaName()!=null) { sb.append("""and a.name like ? """); sqlParams.setString(++i,question.getAreaName()); } instead: StringBuilder sb = new StringBuilder(); sb.append("select a from Area a, CountryCodes cc\n"); sb.append("where cc.isoCode='UA'\n"); sb.append("and a.owner=cc.country'\n"); if (question.getAreaName()!=null) { sb.append("and a.name like ?"); sqlParams.setString(++i,question.getAreaName()); } DETAILS: Multiline strings are part of program text, which begin and ends by three double quotes. (as in groovy and scala) Text withing such brackets processed as multiline string with all rulles as normal Java string literals, except it can be multiline. After parsing multiline string is concatenation of lines with inserted value of system property 'line.separator' between thems. COMPILATION: Multiline strings created and used in .class files exactly as ordinary strings. TESTING: Nothing special. add multiline strings to test-cases. LIBRARY SUPPORT: None. (May be exists sence add simple template processing to standard library, but I think this is goal of next janguage iteration. Now exists many good external frameworks, such as velocity: better wait and standartize support of winner) REFLECTIVE APIS: None OTHER CHANGES: None MIGRATION: None COMPABILITY None REFERENCES http://bugs.sun.com/view_bug.do?bug_id=4165111 From rssh at gradsoft.com.ua Sat Feb 28 22:50:41 2009 From: rssh at gradsoft.com.ua (rssh at gradsoft.com.ua) Date: Sun, 1 Mar 2009 08:50:41 +0200 (EET) Subject: PROPOSAL: Multiline strings In-Reply-To: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> References: <1631da7d0903010058s20803984lcc37a9eb07f9bb7f@mail.gmail.com> Message-ID: <9724b4d386667dda06c3586d7ce0748e.squirrel@wmail.gradsoft.ua> 1. Since we have non-empty discussion, I setup wiki with current proposal ('new string literals instead multiline strings (?)') http://redmine.gradsoft.ua/wiki/java7stringliterals and will try to track all changes as issues. > > Alternatively, you could have a special syntax where 4 quotes strips > out leading whitespace on each line: > Added as issue #161 (http://redmine.gradsoft.ua/issues/show/161) Personally I have no any 'pro' and 'consa' at all. I. e. may be it can be useful in some context, may be not. (Add some type of voting ?) > > Or you could use the C++ style? Ohh, With my experience in maintance C++ systems, this is evil. > > Frankly, to me, the big win would actually not be multiline literals, > but would be escaped String literals. I'm sick of writing all of my > regexps with twice as many \ characters as they need. > Added to proposal. (If you will agree, I also will add you to list of authors) > Jeremy >