<div dir="auto">The discussion of improved TwR came before several times, and as always I think this is a great idea.<div dir="auto">A small problem I have with the proposal is that it breaks the semantics of "try",  as you have no way to catch.</div><div dir="auto"><br></div><div dir="auto">I would in general prefer to have a plan for a complete new stronger enhanced auto-cleanup mechanism and only then break it into small JEPs</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Sep 25, 2023, 11:18 tzengshinfu <<a href="mailto:tzengshinfu@gmail.com" target="_blank" rel="noreferrer">tzengshinfu@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi, Folks,<br>
<br>
Since my last suggestion,<br>
I've conducted some research and stumbled upon the<br>
`@Cleanup`[<a href="https://projectlombok.org/features/Cleanup" rel="noreferrer noreferrer noreferrer" target="_blank">https://projectlombok.org/features/Cleanup</a>] feature in the<br>
popular library `Lombok`.<br>
<br>
Personally, I believe that the existence of this feature indicates a<br>
certain demand, but it's unfortunate that it requires importing the<br>
library, which adds to the maintenance complexity.<br>
I'd like to hear your thoughts on this situation. Is importing Lombok<br>
the best approach?<br>
<br>
P.S. This is my second email to the mail list. If there's anything I<br>
may have overlooked or done incorrectly, please feel free to let me<br>
know. Thank you.<br>
<br>
Thanks for your interest and support,<br>
Hsinfu Tseng<br>
<br>
/* GET BETTER EVERY DAY */<br>
<br>
<br>
tzengshinfu <<a href="mailto:tzengshinfu@gmail.com" rel="noreferrer noreferrer" target="_blank">tzengshinfu@gmail.com</a>> 於 2023年9月4日 週一 上午11:14寫道:<br>
><br>
> Hi, Folks:<br>
><br>
> Recently, I've been using `JBang` to write some script tools, and I<br>
> feel that Java has transformed with modern syntax features like<br>
> `Records`, `Switch Expressions`, and `Pattern Matching`. These newly<br>
> added language features provide developers with more options in<br>
> specific scenarios, almost like giving Java a set of wings.<br>
><br>
> When using the `try-with-resources statement`, I thought it might be<br>
> possible to introduce an additional simplified syntax, which I believe<br>
> would be useful when developing simple, small-scale programs.<br>
> Meanwhile, scenarios requiring resource closure timing specification<br>
> or exception handling can still make use of the original syntax.<br>
><br>
> At first glance, this simplified syntax may seem a bit unusual, but<br>
> considering that `switch` itself encompasses both statements and<br>
> expressions, and that `switch<br>
> expression`[<a href="https://openjdk.org/jeps/361" rel="noreferrer noreferrer noreferrer" target="_blank">https://openjdk.org/jeps/361</a>] also adds a semicolon at the<br>
> end of `}`, perhaps it won't be as difficult to accept.<br>
><br>
> Because it reduces indentation, making the logic clearer and more<br>
> visible, users don't need to consider resource closure timing; they<br>
> can focus solely on business logic. It's possible that in the future,<br>
> the likelihood of using this simplified syntax will increase.<br>
><br>
> In my personal opinion, the original `try-with-resources statement`<br>
> feels like driving a manual transmission car, where I have full<br>
> control over everything. However, if we can let the runtime manage it<br>
> autonomously, it's like driving an automatic car on the long journey<br>
> of coding, and even more effortless.<br>
><br>
> If there could be an alternative approach that is both hassle-free and<br>
> doesn't require altering Java specifications, I hope that experienced<br>
> individuals can share their insights.<br>
><br>
><br>
> Thanks for your interest and support,<br>
> Hsinfu Tseng<br>
><br>
> (Using the JEP template because I've found it helps clarify my thoughts.)<br>
><br>
><br>
> ## Summary<br>
><br>
> Allow omitting the definition of scope when declaring<br>
> `try-with-resources statement`.<br>
><br>
><br>
> ## Goals<br>
><br>
> * Not introducing new scopes to reduce the cognitive burden on<br>
> developers, especially beginners.<br>
> * Reducing the interference of hierarchical indentation to enhance<br>
> code readability.<br>
> * The declaration position of variables is not restricted by<br>
> `try-with-resources statement`.<br>
> * Ensure that resources are released before the current scope ends.<br>
><br>
><br>
> ## Motivation<br>
><br>
> The `try-with-resources statement` simplified resource management in<br>
> Java after version 7. However, its side effect is the necessity to<br>
> declare a scope and, at the same time, it restricts lifetime of the<br>
> variable declared within the scope:<br>
><br>
> ```java<br>
> public class example1 {<br>
>     public static void main(String... args) throws<br>
> FileNotFoundException, IOException {<br>
>         try (BufferedReader reader = new BufferedReader(new<br>
> FileReader("studentName.txt"))) {<br>
>             String studentName = "not found";<br>
>             /* Variable 'studentName' is only alive in the scope of<br>
> try-with-resources statement. */<br>
><br>
>             while ((studentName = reader.readLine()) != null) {<br>
>                 break;<br>
>             }<br>
>         }<br>
><br>
>         System.out.println(studentName);<br>
>         /* Variable 'studentName' cannot be resolved here. */<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> While it's possible to move variable declaration before<br>
> `try-with-resources statement` and modify variable content within the<br>
> scope of `try-with-resources statement`, the actions of declaration,<br>
> assignment, and usage of variables are segmented by the scope of<br>
> `try-with-resources statement`. In practice, we would prefer variable<br>
> declarations to be as close as possible to their usage locations and<br>
> avoid unnecessary<br>
> separation[<a href="https://rules.sonarsource.com/java/RSPEC-1941/" rel="noreferrer noreferrer noreferrer" target="_blank">https://rules.sonarsource.com/java/RSPEC-1941/</a>]:<br>
><br>
> ```java<br>
> public class example2 {<br>
>     public static void main(String... args) throws<br>
> FileNotFoundException, IOException {<br>
>         String studentName = "not found";<br>
><br>
>         // #region<br>
>         // The scope of try-with-resources statement separates<br>
>         // the declaration, assignment, and usage of variable 'studentName'.<br>
>         try (BufferedReader reader = new BufferedReader(new<br>
> FileReader("studentName.txt"))) {<br>
>             while ((studentName = reader.readLine()) != null) {<br>
>                 break;<br>
>             }<br>
>         }<br>
>         // #endregion<br>
><br>
>         System.out.println(studentName);<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> Furthermore, methods that involve multiple resources requiring<br>
> management and dependencies might become cumbersome in terms of syntax<br>
> due to `nested try-with-resources statements`:<br>
><br>
> ```java<br>
> public class example3 {<br>
>     public static void main(String... args) throws SQLException {<br>
>         String jdbcUrl = "jdbcUrl";<br>
>         String username = "username";<br>
>         String password = "password";<br>
><br>
>         try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> username, password)) {<br>
>             String selectSQL = "selectSQL";<br>
>             String studentID = "studentID";<br>
><br>
>             try (PreparedStatement statement =<br>
> conn.prepareStatement(selectSQL)) {<br>
>                 statement.setString(1, studentID);<br>
><br>
>                 try (ResultSet result = statement.executeQuery()) {<br>
>                     String studentName = "not found";<br>
><br>
>                     while (result.next()) {<br>
>                         studentName = result.getString(1);<br>
>                     }<br>
><br>
>                     System.out.println(studentName);<br>
>                 }<br>
>             }<br>
>         }<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> This proposal introduces a shorthand declaration that eliminates the<br>
> scope limitations of `try-with-resources statement`. It enables<br>
> variable declaration, assignment, and usage within the same scope,<br>
> reduces indentation levels for improved code readability (particularly<br>
> in `nested try-with-resources statements`), and defers the timing of<br>
> resource release to the system, ensuring resource disposal before the<br>
> scope in `try-with-resources statement` is declared ends. (Similar to<br>
> Golang's `Defer statement` + resource<br>
> close[<a href="https://go.dev/tour/flowcontrol/12" rel="noreferrer noreferrer noreferrer" target="_blank">https://go.dev/tour/flowcontrol/12</a>], C#'s `using<br>
> declarations`[<a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using" rel="noreferrer noreferrer noreferrer" target="_blank">https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using</a>],<br>
> and Swift's `Defer statement` + resource<br>
> close[<a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/#Defer-Statement" rel="noreferrer noreferrer noreferrer" target="_blank">https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/#Defer-Statement</a>])<br>
><br>
><br>
> ## Description<br>
><br>
> The format of the `simplified try-with-resources statement` is as follows:<br>
><br>
> ```java<br>
> try (resources);/* Change '{}' to ';'. */<br>
><br>
> ```<br>
><br>
> It can be observed that omitting `{}` reduces the indentation, thus<br>
> enhancing code readability by not introducing new scopes. Moreover,<br>
> variable declarations can be positioned either before or after the<br>
> `simplified try-with-resources statement`:<br>
><br>
> ```java<br>
> public class example1_simplified {<br>
>     public static void main(String... args) throws<br>
> FileNotFoundException, IOException {<br>
>         try (BufferedReader reader = new BufferedReader(new<br>
> FileReader("studentName.txt")));<br>
>         String studentName = "not found";<br>
><br>
>         while ((studentName = reader.readLine()) != null) {<br>
>             break;<br>
>         }<br>
><br>
>         System.out.println(studentName);<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> Because it automatically converts the `simplified try-with-resources<br>
> statement` to an equivalent `try-with-resources statement` after<br>
> compilation:<br>
><br>
> ```java<br>
> public class example1_converted {<br>
>     public static void main(String... args) throws<br>
> FileNotFoundException, IOException {<br>
>         try (BufferedReader reader = new BufferedReader(new<br>
> FileReader("studentName.txt"))) {/* Change ';' back to '{'. */<br>
>             String studentName = "not found";<br>
><br>
>             while ((studentName = reader.readLine()) != null) {<br>
>                 break;<br>
>             }<br>
><br>
>             System.out.println(studentName);<br>
>         }/* Add '}' before the current scope ends. */<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> Because the scope of `simplified try-with-resources statement` extends<br>
> until the current scope is terminated, the variable `studentName`,<br>
> which originally couldn't be resolved in `example1`, can now be<br>
> resolved successfully. This allows variable declaration, assignment,<br>
> and usage within the same scope, ensuring that resource close<br>
> operations occur before the current scope ends.<br>
><br>
> Invoking multiple dependent `simplified try-with-resources statements`<br>
> is similar to regular variable declarations, thereby avoiding<br>
> excessive nesting.<br>
><br>
> ```java<br>
> public class example3_simplified {<br>
>     public static void main(String... args) throws SQLException {<br>
>         String jdbcUrl = "jdbcUrl";<br>
>         String username = "username";<br>
>         String password = "password";<br>
><br>
>         try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> username, password));<br>
>         String selectSQL = "selectSQL";<br>
>         String studentID = "studentID";<br>
><br>
>         try (PreparedStatement statement = conn.prepareStatement(selectSQL));<br>
>         statement.setString(1, studentID);<br>
><br>
>         try (ResultSet result = statement.executeQuery());<br>
>         String studentName = "not found";<br>
><br>
>         while (result.next()) {<br>
>             studentName = result.getString(1);<br>
>         }<br>
><br>
>         System.out.println(studentName);<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> It will be converted to equivalent `nested try-with-resources<br>
> statements` after compilation:<br>
><br>
> ```java<br>
> public class example3_converted {<br>
>     public static void main(String... args) throws SQLException {<br>
>         String jdbcUrl = "jdbcUrl";<br>
>         String username = "username";<br>
>         String password = "password";<br>
><br>
>         try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> username, password)) {/* Change ';' back to '{'. */<br>
>         String selectSQL = "selectSQL";<br>
>         String studentID = "studentID";<br>
><br>
>         try (PreparedStatement statement =<br>
> conn.prepareStatement(selectSQL)) {/* Change ';' back to '{'. */<br>
>         statement.setString(1, studentID);<br>
><br>
>         try (ResultSet result = statement.executeQuery()) {/* Change<br>
> ';' back to '{'. */<br>
>         String studentName = "not found";<br>
><br>
>         while (result.next()) {<br>
>             studentName = result.getString(1);<br>
>         }<br>
><br>
>         System.out.println(studentName);<br>
>     }}}}/* Add the corresponding number (in this case, 3) of '}'<br>
> before the current scope ends. */<br>
> }<br>
><br>
> ```<br>
><br>
> After code formatting:<br>
><br>
> ```java<br>
> public class example3_formatted {<br>
>     public static void main(String... args) throws SQLException {<br>
>         String jdbcUrl = "jdbcUrl";<br>
>         String username = "username";<br>
>         String password = "password";<br>
><br>
>         try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> username, password)) {<br>
>             String selectSQL = "selectSQL";<br>
>             String studentID = "studentID";<br>
><br>
>             try (PreparedStatement statement =<br>
> conn.prepareStatement(selectSQL)) {<br>
>                 statement.setString(1, studentID);<br>
><br>
>                 try (ResultSet result = statement.executeQuery()) {<br>
>                     String studentName = "not found";<br>
><br>
>                     while (result.next()) {<br>
>                         studentName = result.getString(1);<br>
>                     }<br>
><br>
>                     System.out.println(studentName);<br>
>                 }<br>
>             }<br>
>         }<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> Comparing the code structures of `example3_simplified` and<br>
> `example3_formatted`, it is evident that the usage of `simplified<br>
> try-with-resources statement` enhances code readability by<br>
> significantly reducing nested indentation levels. Additionally, it can<br>
> be observed that in the converted `nested try-with-resources<br>
> statements`, resource close actions will be executed in reverse order<br>
> of declaration, just before the current scope ends.<br>
><br>
> If coupled with `JEP 445: Unnamed Classes and Instance Main Methods<br>
> (Preview)`[<a href="https://openjdk.org/jeps/445" rel="noreferrer noreferrer noreferrer" target="_blank">https://openjdk.org/jeps/445</a>], it becomes convenient to<br>
> create a simple, small-scale program:<br>
><br>
> ```java<br>
> String jdbcUrl = "jdbcUrl";<br>
> String username = "username";<br>
> String password = "password";<br>
> String selectSQL = "selectSQL";<br>
> String studentID = "studentID";<br>
><br>
> void main() throws SQLException {<br>
>     try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> username, password));<br>
>     try (PreparedStatement statement = conn.prepareStatement(selectSQL));<br>
>     statement.setString(1, studentID);<br>
><br>
>     try (ResultSet result = statement.executeQuery());<br>
>     String studentName = "not found";<br>
><br>
>     while (result.next()) {<br>
>         studentName = result.getString(1);<br>
>     }<br>
><br>
>     System.out.println(studentName);<br>
> }<br>
><br>
> ```<br>
><br>
><br>
> ## Alternatives<br>
><br>
> * One approach to mitigate the impact on readability caused by deeply<br>
> `nested try-with-resources statements` is to consolidate multiple<br>
> resources within the same `try-with-resources statement` as much as<br>
> possible. However, formatting multiple resources with line breaks can<br>
> also disrupt visual clarity, and furthermore, it's not always feasible<br>
> to close many resources simultaneously:<br>
><br>
> ```java<br>
> public class alternative1 {<br>
>     public static void main(String... args) throws SQLException {<br>
>         String jdbcUrl = "jdbcUrl";<br>
>         String username = "username";<br>
>         String password = "password";<br>
>         String selectSQL = "selectSQL";<br>
>         String studentID = "studentID";<br>
><br>
>         try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> username, password);<br>
>                 PreparedStatement statement =<br>
> conn.prepareStatement(selectSQL)) {<br>
>         /* In this case, there are only 2 resources, but if there are 3 or more,<br>
>            it will become even less aesthetically pleasing. */<br>
><br>
>             statement.setString(1, studentID);<br>
><br>
>             try (ResultSet result = statement.executeQuery()) {<br>
>             /* ResultSet 'result' cannot be closed simultaneously with<br>
> PreparedStatement 'statement'<br>
>                because PreparedStatement 'statement' needs parameter<br>
> configuration first. */<br>
>                 String studentName = "not found";<br>
><br>
>                 while (result.next()) {<br>
>                     studentName = result.getString(1);<br>
>                 }<br>
><br>
>                 return studentName;<br>
>             }<br>
>         }<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> * Alternatively, creating a separate method to confine the scope of<br>
> managed resources within the method can be done, but it necessitates<br>
> 'naming' the new<br>
> method[<a href="https://www.karlton.org/2017/12/naming-things-hard/" rel="noreferrer noreferrer noreferrer" target="_blank">https://www.karlton.org/2017/12/naming-things-hard/</a>]. This<br>
> approach simply shifts complexity to the interior of additional<br>
> method, which may not be conducive to creating simple, small-scale<br>
> programs:<br>
><br>
> ```java<br>
> public class alternative2 {<br>
>     public static void main(String... args) throws SQLException {<br>
>         String selectSQL = "selectSQL";<br>
>         String studentID = "studentID";<br>
>         String studentName = getStudentName(selectSQL, studentID);<br>
><br>
>         System.out.println(studentName);<br>
>     }<br>
><br>
>     public static String getStudentName(String sql, String studentID)<br>
> throws SQLException {<br>
>         String jdbcUrl = "jdbcUrl";<br>
>         String username = "username";<br>
>         String password = "password";<br>
><br>
>         try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> username, password)) {<br>
>             try (PreparedStatement statement = conn.prepareStatement(sql)) {<br>
>                 statement.setString(1, studentID);<br>
><br>
>                 try (ResultSet result = statement.executeQuery()) {<br>
>                     String studentName = "not found";<br>
><br>
>                     while (result.next()) {<br>
>                         studentName = result.getString(1);<br>
>                     }<br>
><br>
>                     return studentName;<br>
>                 }<br>
>             }<br>
>         }<br>
>     }<br>
> }<br>
><br>
> ```<br>
><br>
> /* GET BETTER EVERY DAY */<br>
</blockquote></div>