From joe.darcy at oracle.com Thu Aug 5 09:38:52 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Thu, 05 Aug 2010 09:38:52 -0700 Subject: Updated ARM Spec In-Reply-To: <4C3F8142.2030203@oracle.com> References: <4C3F8142.2030203@oracle.com> Message-ID: <4C5AE91C.1070908@oracle.com> Joe Darcy wrote: > Greetings. > > Starting with Project Coin proposal for Automatic Resource Management > (ARM), in consultation with Josh Bloch, Maurizio, Jon, and others, Alex > and I have produced a specification for ARM blocks that is much closer > to Java Language Specification (JLS) style and rigor. The specification > involves changes to the existing JLS section 14.20 "The try statement," > and will eventually introduce a new subsection 14.20.3 "Execution of > try-with-resources," although the specification below is not partitioned > as such. Non-normative comments about the specification text below > appear inside "[]". Differences between the new specification and the > earlier Project Coin proposal for ARM are discussed after the specification. > > > [snip] > * Adjustments to the suppressed exception logic: in the present > specification, an incoming primary exception will suppress an Exception > thrown by a close method; however, if the close method throws an error, > that error is propagated out without suppressing an incoming primary > exception. Possible alternatives include having a primary exception in a > try-with-resource statement suppress all subsequent Throwables > originating in the statement and having a non-Exception thrown by a > close suppress any incoming primary exception. > > These alternatives could be implemented by replacing the translated code > > try { > #resource.close(); > } catch(Exception #suppressedException) { > > #primaryException.addSuppressedException(#suppressedException); > } > > with > > try { > #resource.close(); > } catch(Throwable #suppressedException) { > > #primaryException.addSuppressedException(#suppressedException); > } > > or > > try { > #resource.close(); > } catch(Exception #suppressedException) { > > #primaryException.addSuppressedException(#suppressedException); > } catch(Throwable #throwable) { > #throwable.addSuppressedException(#primaryException); > throw #throwable; > } > > respectively. > > -Joe > We've decided to change the specification to the first alternative, where an incoming primary suppresses all Throwables rather than just subclasses of java.lang.Exception. The initial code push [1] actually implemented those semantics; a test has been added to verify the newly specified behavior [2]. -Joe [1] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/13354e1abba7 [2] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/38e2c23309f1 From ullenboom at googlemail.com Fri Aug 6 02:00:48 2010 From: ullenboom at googlemail.com (Christian Ullenboom) Date: Fri, 6 Aug 2010 11:00:48 +0200 Subject: Will we finally get Language support for Collections? Message-ID: Joseph ones wrote that there will be "Language support for Collections" (http://blogs.sun.com/darcy/entry/project_coin_final_five). Is this idea cancelled? Best regards, Chris From neal at gafter.com Thu Aug 12 20:28:54 2010 From: neal at gafter.com (Neal Gafter) Date: Thu, 12 Aug 2010 20:28:54 -0700 Subject: Updated ARM Spec In-Reply-To: <4C5AE91C.1070908@oracle.com> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> Message-ID: When a stack overflow exception suppresses another exception, I assume it's suppressed exception list will be set. But since there is only one such exception allocated by the VM, this will overwrite any data previously stored there. Will the VM be modified to comply with this specification by allocating a new stack-overflow exception each time? Same question for out-of-memory error. On Thursday, August 5, 2010, Joe Darcy wrote: > Joe Darcy wrote: >> Greetings. >> >> Starting with Project Coin proposal for Automatic Resource Management >> (ARM), in consultation with Josh Bloch, Maurizio, Jon, and others, Alex >> and I have produced a specification for ARM blocks that is much closer >> to Java Language Specification (JLS) style and rigor. The specification >> involves changes to the existing JLS section 14.20 "The try statement," >> and will eventually introduce a new subsection 14.20.3 "Execution of >> try-with-resources," although the specification below is not partitioned >> as such. Non-normative comments about the specification text below >> appear inside "[]". Differences between the new specification and the >> earlier Project Coin proposal for ARM are discussed after the specification. >> >> >> > > [snip] > >> * Adjustments to the suppressed exception logic: in the present >> specification, an incoming primary exception will suppress an Exception >> thrown by a close method; however, if the close method throws an error, >> that error is propagated out without suppressing an incoming primary >> exception. Possible alternatives include having a primary exception in a >> try-with-resource statement suppress all subsequent Throwables >> originating in the statement and having a non-Exception thrown by a >> close suppress any incoming primary exception. >> >> These alternatives could be implemented by replacing the translated code >> >> ? ? ? ? ? ? ? try { >> ? ? ? ? ? ? ? ? #resource.close(); >> ? ? ? ? ? ? ? } catch(Exception #suppressedException) { >> >> #primaryException.addSuppressedException(#suppressedException); >> ? ? ? ? ? ? ? } >> >> with >> >> ? ? ? ? ? ? ? try { >> ? ? ? ? ? ? ? ? #resource.close(); >> ? ? ? ? ? ? ? } catch(Throwable #suppressedException) { >> >> #primaryException.addSuppressedException(#suppressedException); >> ? ? ? ? ? ? ? } >> >> or >> >> ? ? ? ? ? ? ? try { >> ? ? ? ? ? ? ? ? #resource.close(); >> ? ? ? ? ? ? ? } catch(Exception #suppressedException) { >> >> #primaryException.addSuppressedException(#suppressedException); >> ? ? ? ? ? ? ? } catch(Throwable #throwable) { >> ? ? ? ? ? ? ? ? #throwable.addSuppressedException(#primaryException); >> ? ? ? ? ? ? ? ? throw #throwable; >> ? ? ? ? ? ? ? } >> >> respectively. >> >> -Joe >> > > We've decided to change the specification to the first alternative, > where an incoming primary suppresses all Throwables rather than just > subclasses of java.lang.Exception. > > The initial code push [1] actually implemented those semantics; a test > has been added to verify the newly specified behavior [2]. > > -Joe > > [1] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/13354e1abba7 > [2] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/38e2c23309f1 > > > From tball at google.com Thu Aug 12 22:28:39 2010 From: tball at google.com (Tom Ball) Date: Thu, 12 Aug 2010 22:28:39 -0700 Subject: Updated ARM Spec In-Reply-To: References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> Message-ID: IMHO, the point of syntactic sugar is to eliminate boilerplate code and/or patterns that are difficult to implement correctly, not to solve new CS problems, so any new sugar should be able to be fully described with existing Java syntax. For syntactic sugar enhancements, I've found it much easier to get engineers to reach consensus on a clear code example than on a spec describing it. Wasn't that how the enhanced for loops were designed in Java 5? So what Java 6 code would you write that fully addresses your concerns here? For my own projects, I'd just bail rather than invest in handling a rare occurrence like this (at least it should be rare), but that bad attitude is probably why I rarely contribute to language design discussions. :-) Tom If agreement can be reached on exactly what code we're On Thu, Aug 12, 2010 at 8:28 PM, Neal Gafter wrote: > When a stack overflow exception suppresses another exception, I assume > it's suppressed exception list will be set. But since there is only > one such exception allocated by the VM, this will overwrite any data > previously stored there. Will the VM be modified to comply with this > specification by allocating a new stack-overflow exception each time? > Same question for out-of-memory error. > > On Thursday, August 5, 2010, Joe Darcy wrote: > > Joe Darcy wrote: > >> Greetings. > >> > >> Starting with Project Coin proposal for Automatic Resource Management > >> (ARM), in consultation with Josh Bloch, Maurizio, Jon, and others, Alex > >> and I have produced a specification for ARM blocks that is much closer > >> to Java Language Specification (JLS) style and rigor. The specification > >> involves changes to the existing JLS section 14.20 "The try statement," > >> and will eventually introduce a new subsection 14.20.3 "Execution of > >> try-with-resources," although the specification below is not partitioned > >> as such. Non-normative comments about the specification text below > >> appear inside "[]". Differences between the new specification and the > >> earlier Project Coin proposal for ARM are discussed after the > specification. > >> > >> > >> > > > > [snip] > > > >> * Adjustments to the suppressed exception logic: in the present > >> specification, an incoming primary exception will suppress an Exception > >> thrown by a close method; however, if the close method throws an error, > >> that error is propagated out without suppressing an incoming primary > >> exception. Possible alternatives include having a primary exception in a > >> try-with-resource statement suppress all subsequent Throwables > >> originating in the statement and having a non-Exception thrown by a > >> close suppress any incoming primary exception. > >> > >> These alternatives could be implemented by replacing the translated code > >> > >> try { > >> #resource.close(); > >> } catch(Exception #suppressedException) { > >> > >> #primaryException.addSuppressedException(#suppressedException); > >> } > >> > >> with > >> > >> try { > >> #resource.close(); > >> } catch(Throwable #suppressedException) { > >> > >> #primaryException.addSuppressedException(#suppressedException); > >> } > >> > >> or > >> > >> try { > >> #resource.close(); > >> } catch(Exception #suppressedException) { > >> > >> #primaryException.addSuppressedException(#suppressedException); > >> } catch(Throwable #throwable) { > >> #throwable.addSuppressedException(#primaryException); > >> throw #throwable; > >> } > >> > >> respectively. > >> > >> -Joe > >> > > > > We've decided to change the specification to the first alternative, > > where an incoming primary suppresses all Throwables rather than just > > subclasses of java.lang.Exception. > > > > The initial code push [1] actually implemented those semantics; a test > > has been added to verify the newly specified behavior [2]. > > > > -Joe > > > > [1] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/13354e1abba7 > > [2] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/38e2c23309f1 > > > > > > > > From forax at univ-mlv.fr Fri Aug 13 05:41:31 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Fri, 13 Aug 2010 14:41:31 +0200 Subject: Updated ARM Spec In-Reply-To: References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> Message-ID: <4C653D7B.6020001@univ-mlv.fr> Le 13/08/2010 05:28, Neal Gafter a ?crit : > When a stack overflow exception suppresses another exception, I assume > it's suppressed exception list will be set. But since there is only > one such exception allocated by the VM, this will overwrite any data > previously stored there. Will the VM be modified to comply with this > specification by allocating a new stack-overflow exception each time? > Same question for out-of-memory error. > This problem already exists with jdk6. This code change the stack trace of permanently allocated OutOfMerroryError. public static void main(String[] args) { Error last = null; for(int i=0; i<100; i++) { try { Object o = new int[Integer.MAX_VALUE]; } catch (Error e) { StackTraceElement[] stackTrace = e.getStackTrace(); if (stackTrace != null && stackTrace.length>0 && stackTrace[0].getLineNumber() == -3) { e.printStackTrace(); return; } if (last == e) { StackTraceElement element = new StackTraceElement("Foo", "foo", null, -3); e.setStackTrace(new StackTraceElement[]{element}); } last = e; } } } To avoid that the VM has to clear the stacktrace when using the default error: in universe.cpp, in Universe::gen_out_of_memory_error: if (next < 0) { // all preallocated errors have been used. // return default + java_lang_Throwable::clear_stacktrace(default_err); return default_err; } else { And we should do the same for the field suppressed exceptions. R?mi From neal at gafter.com Fri Aug 13 09:31:27 2010 From: neal at gafter.com (Neal Gafter) Date: Fri, 13 Aug 2010 08:31:27 -0800 Subject: Updated ARM Spec In-Reply-To: References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> Message-ID: <5CB239A1-2297-4953-AB36-BC8F1E0E08EC@gafter.com> Bailing on stack overflow is a horrible approach (notwithstanding my employer's choice). At the risk of beating a dead horse, I do not think that the stageful "suppressed exceptions" approach scales from a software engineering point of view. See the archives for my suggested alternatives. -Neal On Aug 12, 2010, at 9:28 PM, Tom Ball wrote: > IMHO, the point of syntactic sugar is to eliminate boilerplate code and/or patterns that are difficult to implement correctly, not to solve new CS problems, so any new sugar should be able to be fully described with existing Java syntax. For syntactic sugar enhancements, I've found it much easier to get engineers to reach consensus on a clear code example than on a spec describing it. Wasn't that how the enhanced for loops were designed in Java 5? > > So what Java 6 code would you write that fully addresses your concerns here? For my own projects, I'd just bail rather than invest in handling a rare occurrence like this (at least it should be rare), but that bad attitude is probably why I rarely contribute to language design discussions. :-) > > Tom > > If agreement can be reached on exactly what code we're > > On Thu, Aug 12, 2010 at 8:28 PM, Neal Gafter wrote: > When a stack overflow exception suppresses another exception, I assume > it's suppressed exception list will be set. But since there is only > one such exception allocated by the VM, this will overwrite any data > previously stored there. Will the VM be modified to comply with this > specification by allocating a new stack-overflow exception each time? > Same question for out-of-memory error. > > On Thursday, August 5, 2010, Joe Darcy wrote: > > Joe Darcy wrote: > >> Greetings. > >> > >> Starting with Project Coin proposal for Automatic Resource Management > >> (ARM), in consultation with Josh Bloch, Maurizio, Jon, and others, Alex > >> and I have produced a specification for ARM blocks that is much closer > >> to Java Language Specification (JLS) style and rigor. The specification > >> involves changes to the existing JLS section 14.20 "The try statement," > >> and will eventually introduce a new subsection 14.20.3 "Execution of > >> try-with-resources," although the specification below is not partitioned > >> as such. Non-normative comments about the specification text below > >> appear inside "[]". Differences between the new specification and the > >> earlier Project Coin proposal for ARM are discussed after the specification. > >> > >> > >> > > > > [snip] > > > >> * Adjustments to the suppressed exception logic: in the present > >> specification, an incoming primary exception will suppress an Exception > >> thrown by a close method; however, if the close method throws an error, > >> that error is propagated out without suppressing an incoming primary > >> exception. Possible alternatives include having a primary exception in a > >> try-with-resource statement suppress all subsequent Throwables > >> originating in the statement and having a non-Exception thrown by a > >> close suppress any incoming primary exception. > >> > >> These alternatives could be implemented by replacing the translated code > >> > >> try { > >> #resource.close(); > >> } catch(Exception #suppressedException) { > >> > >> #primaryException.addSuppressedException(#suppressedException); > >> } > >> > >> with > >> > >> try { > >> #resource.close(); > >> } catch(Throwable #suppressedException) { > >> > >> #primaryException.addSuppressedException(#suppressedException); > >> } > >> > >> or > >> > >> try { > >> #resource.close(); > >> } catch(Exception #suppressedException) { > >> > >> #primaryException.addSuppressedException(#suppressedException); > >> } catch(Throwable #throwable) { > >> #throwable.addSuppressedException(#primaryException); > >> throw #throwable; > >> } > >> > >> respectively. > >> > >> -Joe > >> > > > > We've decided to change the specification to the first alternative, > > where an incoming primary suppresses all Throwables rather than just > > subclasses of java.lang.Exception. > > > > The initial code push [1] actually implemented those semantics; a test > > has been added to verify the newly specified behavior [2]. > > > > -Joe > > > > [1] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/13354e1abba7 > > [2] http://hg.openjdk.java.net/jdk7/tl/langtools/rev/38e2c23309f1 > > > > > > > > From joe.darcy at oracle.com Fri Aug 20 13:45:42 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Fri, 20 Aug 2010 13:45:42 -0700 Subject: Updated ARM Spec In-Reply-To: <4C653D7B.6020001@univ-mlv.fr> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> Message-ID: <4C6EE976.4010802@oracle.com> R?mi Forax wrote: > Le 13/08/2010 05:28, Neal Gafter a ?crit : > >> When a stack overflow exception suppresses another exception, I assume >> it's suppressed exception list will be set. But since there is only >> one such exception allocated by the VM, this will overwrite any data >> previously stored there. Will the VM be modified to comply with this >> specification by allocating a new stack-overflow exception each time? >> Same question for out-of-memory error. >> >> > > This problem already exists with jdk6. > This code change the stack trace of permanently allocated OutOfMerroryError. > > public static void main(String[] args) { > Error last = null; > > for(int i=0; i<100; i++) { > try { > Object o = new int[Integer.MAX_VALUE]; > } catch (Error e) { > StackTraceElement[] stackTrace = e.getStackTrace(); > if (stackTrace != null && stackTrace.length>0 && > stackTrace[0].getLineNumber() == -3) { > e.printStackTrace(); > return; > } > > if (last == e) { > StackTraceElement element = new StackTraceElement("Foo", > "foo", null, -3); > e.setStackTrace(new StackTraceElement[]{element}); > } > last = e; > } > } > } > > > > To avoid that the VM has to clear the stacktrace when using the default > error: > in universe.cpp, in Universe::gen_out_of_memory_error: > > if (next < 0) { > // all preallocated errors have been used. > // return default > + java_lang_Throwable::clear_stacktrace(default_err); > return default_err; > } else { > > > And we should do the same for the field suppressed exceptions. > > R?mi > > Thanks for the suggestion R?mi; I'm also checking with the HotSpot folks to see if any other kinds of exceptions need to be handled specially. -Joe From pbenedict at apache.org Fri Aug 20 13:45:41 2010 From: pbenedict at apache.org (Paul Benedict) Date: Fri, 20 Aug 2010 15:45:41 -0500 Subject: Updated ARM Spec In-Reply-To: <4C6EE976.4010802@oracle.com> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C6EE976.4010802@oracle.com> Message-ID: I still think Errors should not be swallowed. They indicate major problems and should terminate the use case. On Fri, Aug 20, 2010 at 3:45 PM, Joe Darcy wrote: > R?mi Forax wrote: >> Le 13/08/2010 05:28, Neal Gafter a ?crit : >> >>> When a stack overflow exception suppresses another exception, I assume >>> it's suppressed exception list will be set. ?But since there is only >>> one such exception allocated by the VM, this will overwrite any data >>> previously stored there. ?Will the VM be modified to comply with this >>> specification by allocating a new stack-overflow exception each time? >>> Same question for out-of-memory error. >>> >>> >> >> This problem already exists with jdk6. >> This code change the stack trace of permanently allocated OutOfMerroryError. >> >> ? ?public static void main(String[] args) { >> ? ? ?Error last = null; >> >> ? ? ?for(int i=0; i<100; i++) { >> ? ? ? ?try { >> ? ? ? ? ?Object o = new int[Integer.MAX_VALUE]; >> ? ? ? ?} catch (Error e) { >> ? ? ? ? ?StackTraceElement[] stackTrace = e.getStackTrace(); >> ? ? ? ? ?if (stackTrace != null && stackTrace.length>0 && >> stackTrace[0].getLineNumber() == -3) { >> ? ? ? ? ? ?e.printStackTrace(); >> ? ? ? ? ? ?return; >> ? ? ? ? ?} >> >> ? ? ? ? ?if (last == e) { >> ? ? ? ? ? ?StackTraceElement element = new StackTraceElement("Foo", >> "foo", null, -3); >> ? ? ? ? ? ?e.setStackTrace(new StackTraceElement[]{element}); >> ? ? ? ? ?} >> ? ? ? ? ?last = e; >> ? ? ? ?} >> ? ? ?} >> ? ?} >> >> >> >> To avoid that the VM has to clear the stacktrace when using the default >> error: >> in universe.cpp, in Universe::gen_out_of_memory_error: >> >> ? ?if (next < 0) { >> ? ? ? ?// all preallocated errors have been used. >> ? ? ? ?// return default >> + ? ?java_lang_Throwable::clear_stacktrace(default_err); >> ? ? ? ?return default_err; >> ? ? ?} else { >> >> >> And we should do the same for the field suppressed exceptions. >> >> R?mi >> >> > > Thanks for the suggestion R?mi; I'm also checking with the HotSpot folks > to see if any other kinds of exceptions need to be handled specially. > > -Joe > > From mandy.chung at oracle.com Fri Aug 20 14:50:52 2010 From: mandy.chung at oracle.com (Mandy Chung) Date: Fri, 20 Aug 2010 14:50:52 -0700 Subject: Updated ARM Spec In-Reply-To: <4C653D7B.6020001@univ-mlv.fr> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> Message-ID: <4C6EF8BC.6000407@oracle.com> Hi Remi, R?mi Forax wrote: > Le 13/08/2010 05:28, Neal Gafter a ?crit : >> When a stack overflow exception suppresses another exception, I assume >> it's suppressed exception list will be set. But since there is only >> one such exception allocated by the VM, this will overwrite any data >> previously stored there. Will the VM be modified to comply with this >> specification by allocating a new stack-overflow exception each time? >> Same question for out-of-memory error. >> > > This problem already exists with jdk6. > This code change the stack trace of permanently allocated > OutOfMerroryError. > > public static void main(String[] args) { > Error last = null; > > for(int i=0; i<100; i++) { > try { > Object o = new int[Integer.MAX_VALUE]; > } catch (Error e) { > StackTraceElement[] stackTrace = e.getStackTrace(); > if (stackTrace != null && stackTrace.length>0 && > stackTrace[0].getLineNumber() == -3) { > e.printStackTrace(); > return; > } > > if (last == e) { > StackTraceElement element = new StackTraceElement("Foo", > "foo", null, -3); > e.setStackTrace(new StackTraceElement[]{element}); > } > last = e; > } > } > } > > > > To avoid that the VM has to clear the stacktrace when using the > default error: > in universe.cpp, in Universe::gen_out_of_memory_error: > > if (next < 0) { > // all preallocated errors have been used. > // return default > + java_lang_Throwable::clear_stacktrace(default_err); > return default_err; > } else { > > This is indeed a bug and I file 6978918 to fix it. We should clear the stacktrace and the suppressed exception fields as you suggest. Thanks Mandy > And we should do the same for the field suppressed exceptions. > > R?mi > From joe.darcy at oracle.com Fri Aug 20 17:08:35 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Fri, 20 Aug 2010 17:08:35 -0700 Subject: try-with-resources (ARM block) support in JDK 7 build 105 Message-ID: <4C6F1903.5050208@oracle.com> Hello. The currently available builds of JDK 7 include language and API support for try-with-resources (ARM blocks): http://download.java.net/jdk7/ We're curious to get feedback on how try-with-resources works in practice, so please download the build, use the feature to on your favorite Closeable type, and report back on how it goes. -Joe From dalibor.topic at oracle.com Sat Aug 21 01:14:18 2010 From: dalibor.topic at oracle.com (Dalibor Topic) Date: Sat, 21 Aug 2010 10:14:18 +0200 Subject: try-with-resources (ARM block) support in JDK 7 build 105 In-Reply-To: <4C6F1903.5050208@oracle.com> References: <4C6F1903.5050208@oracle.com> Message-ID: <4C6F8ADA.7070504@oracle.com> On 8/21/10 2:08 AM, Joe Darcy wrote: > Hello. > > The currently available builds of JDK 7 include language and API support > for try-with-resources (ARM blocks): > > http://download.java.net/jdk7/ > > We're curious to get feedback on how try-with-resources works in > practice, so please download the build, use the feature to on your > favorite Closeable type, and report back on how it goes. JDK 7 binary snapshot releases are at http://download.java.net/jdk7/binaries/ and cover Windows on x86 & x64, Solaris on SPARC, x86 & x64 and Linux on x86 & x64. If you're not on one of these platforms, your feedback is still valuable, you'll just have to do the build yourself from the sources - for Mac users, please see the BSD port wiki for details on that: http://wikis.sun.com/display/OpenJDK/BSDPort cheers, dalibor topic -- Oracle Dalibor Topic | Java F/OSS Ambassador Phone: +494023646738 | | | Mobile: +491772664192 Oracle Java Platform Group ORACLE Deutschland B.V. & Co. KG | Nagelsweg 55 | 20097 Hamburg ORACLE Deutschland B.V. & Co. KG Hauptverwaltung: Riesstr. 25, D-80992 M?nchen Registergericht: Amtsgericht M?nchen, HRA 95603 Komplement?rin: ORACLE Deutschland Verwaltung B.V. Rijnzathe 6, 3454PV De Meern, Niederlande Handelsregister der Handelskammer Midden-Niederlande, Nr. 30143697 Gesch?ftsf?hrer: J?rgen Kunz, Marcel van de Molen, Alexander van der Ven Green Oracle Oracle is committed to developing practices and products that help protect the environment From forax at univ-mlv.fr Sat Aug 21 02:27:27 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 21 Aug 2010 11:27:27 +0200 Subject: Updated ARM Spec In-Reply-To: <4C6EF8BC.6000407@oracle.com> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C6EF8BC.6000407@oracle.com> Message-ID: <4C6F9BFF.6000101@univ-mlv.fr> Le 20/08/2010 23:50, Mandy Chung a ?crit : > Hi Remi, Thanks Mandy. R?mi > > R?mi Forax wrote: >> Le 13/08/2010 05:28, Neal Gafter a ?crit : >>> When a stack overflow exception suppresses another exception, I assume >>> it's suppressed exception list will be set. But since there is only >>> one such exception allocated by the VM, this will overwrite any data >>> previously stored there. Will the VM be modified to comply with this >>> specification by allocating a new stack-overflow exception each time? >>> Same question for out-of-memory error. >> >> This problem already exists with jdk6. >> This code change the stack trace of permanently allocated >> OutOfMerroryError. >> >> public static void main(String[] args) { >> Error last = null; >> >> for(int i=0; i<100; i++) { >> try { >> Object o = new int[Integer.MAX_VALUE]; >> } catch (Error e) { >> StackTraceElement[] stackTrace = e.getStackTrace(); >> if (stackTrace != null && stackTrace.length>0 && >> stackTrace[0].getLineNumber() == -3) { >> e.printStackTrace(); >> return; >> } >> >> if (last == e) { >> StackTraceElement element = new StackTraceElement("Foo", >> "foo", null, -3); >> e.setStackTrace(new StackTraceElement[]{element}); >> } >> last = e; >> } >> } >> } >> >> >> >> To avoid that the VM has to clear the stacktrace when using the >> default error: >> in universe.cpp, in Universe::gen_out_of_memory_error: >> >> if (next < 0) { >> // all preallocated errors have been used. >> // return default >> + java_lang_Throwable::clear_stacktrace(default_err); >> return default_err; >> } else { >> >> > > This is indeed a bug and I file 6978918 to fix it. We should clear > the stacktrace and the suppressed exception fields as you suggest. > Thanks > Mandy > >> And we should do the same for the field suppressed exceptions. >> >> R?mi >> > From forax at univ-mlv.fr Mon Aug 23 03:15:42 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 23 Aug 2010 12:15:42 +0200 Subject: Updated ARM Spec In-Reply-To: <4C7240FF.7020209@oracle.com> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C7240FF.7020209@oracle.com> Message-ID: <4C724A4E.4090804@univ-mlv.fr> Le 23/08/2010 11:35, David Holmes a ?crit : > Remi, > > I think there is some confusion over the use of pre-allocated > exceptions here. For OutOfMemoryEror we have two kinds of > pre-allocated exceptions for the general case of exhausting the Java > heap. > > First we have PreallocatedOutOfMemoryErrorCount (default 4) OOME > instances, which have space for a backtrace allocated. These instances > can only be thrown once and so can only have one real backtrace. Of > course application code can mutate that stacktrace but that won't > affect any other point where OOME is thrown as it won't be that OOME. > > In addition there is one preallocated OOME instance that has no > backtrace allocated for it. Hence when it gets thrown no backtrace is > filled in and there is nothing for the application code to mutate. > This single instance can be thrown by multiple threads in multiple > circumstances without harm. Here is the bug, the application can mutate the default OOME using setStackTrace(). > > Similarly there are a bunch of pre-allocated OOME objects, without > backtraces, for special conditions like maximum array size being > exceeded etc. > > None of the other special pre-allocated instances (NPE, > ArithmeticException, ...) have a backtrace either. > > So there is no need for the VM to clear the backtrace before throwing > any pre-allocated exception instance. > > The "suppressedException" array as I currently understand it would > need to be cleared, if the pre-allocated instances with no backtrace > can still contain "suppressedExceptions" - which I believe they can. > > Aside: StackOverflowException is created on demand, not pre-allocated, > in Hotspot. > > David Holmes > ------------ R?mi From forax at univ-mlv.fr Mon Aug 23 05:56:56 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 23 Aug 2010 14:56:56 +0200 Subject: Updated ARM Spec In-Reply-To: <4C724D9E.8030100@oracle.com> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C7240FF.7020209@oracle.com> <4C724471.9010606@oracle.com> <4C72480B.3050104@univ-mlv.fr> <4C7248F3.4010200@oracle.com> <4C724C26.6040709@univ-mlv.fr> <4C724D9E.8030100@oracle.com> Message-ID: <4C727018.5090409@univ-mlv.fr> Le 23/08/2010 12:29, David Holmes a ?crit : > R?mi Forax said the following on 08/23/10 20:23: >> Le 23/08/2010 12:09, David Holmes a ?crit : >>> R?mi Forax said the following on 08/23/10 20:06: >>>> You can explicitly call setStackTrace() on a shared immutable >>>> exception, hence there is a problem. >>>> addSupressedExceptions() will have the same issue. >>> >>> I stand corrected. The Java side of the code couldn't care less >>> about the VM level backtrace - it just installs a Java array. :( >>> >>>> I think the fix is to: >>>> - silently discard the stack trace taken as argument of >>>> setStackTrace() if the cause is 'null' (or not 'this') >>>> - silently don't register suppressed-exceptions if cause is 'null' >>> >>> I think the Java code should be able to recognize a Throwable >>> instance that should not allow these things to be set, and simply >>> ignore the request. However that is a change in the spec for >>> setStackTrace. >> >> Yes, setStackTrace() can 'not succeed'. >> And the way to recognize such Throwable instance is to check is the >> field 'cause' is null. > > Except if someone invokes setCause(null). setCause(null) should set the field cause to this. For Throwable(null) and Throwable(message, null), null should also be escaped. The other solution is to use the field suppressedExceptions with the invariant that if it's null, it's an immutable shared exception. > > By the way, probing further, the non-OOME shared pre-allocated > instances do not guard themselves against fillInStackTrace being > invoked upon them. That is arguably an additional bug. I say arguably > simply because in the circumstances under which those other exceptions > are thrown, having a misleading stacktrace is probably the least of > the application's worries. yes, you right. > > David R?mi > > >>> Suppressed-exceptions could then be modelled like backtrace support >>> - an optional facility generally used but ignored for the >>> pre-allocated immutable instances. >> >> Yes, and the spec must be also updated accordingly. >> >>> >>> David >> >> R?mi From David.Holmes at oracle.com Mon Aug 23 02:35:59 2010 From: David.Holmes at oracle.com (David Holmes) Date: Mon, 23 Aug 2010 19:35:59 +1000 Subject: Updated ARM Spec In-Reply-To: <4C653D7B.6020001@univ-mlv.fr> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> Message-ID: <4C7240FF.7020209@oracle.com> Remi, I think there is some confusion over the use of pre-allocated exceptions here. For OutOfMemoryEror we have two kinds of pre-allocated exceptions for the general case of exhausting the Java heap. First we have PreallocatedOutOfMemoryErrorCount (default 4) OOME instances, which have space for a backtrace allocated. These instances can only be thrown once and so can only have one real backtrace. Of course application code can mutate that stacktrace but that won't affect any other point where OOME is thrown as it won't be that OOME. In addition there is one preallocated OOME instance that has no backtrace allocated for it. Hence when it gets thrown no backtrace is filled in and there is nothing for the application code to mutate. This single instance can be thrown by multiple threads in multiple circumstances without harm. Similarly there are a bunch of pre-allocated OOME objects, without backtraces, for special conditions like maximum array size being exceeded etc. None of the other special pre-allocated instances (NPE, ArithmeticException, ...) have a backtrace either. So there is no need for the VM to clear the backtrace before throwing any pre-allocated exception instance. The "suppressedException" array as I currently understand it would need to be cleared, if the pre-allocated instances with no backtrace can still contain "suppressedExceptions" - which I believe they can. Aside: StackOverflowException is created on demand, not pre-allocated, in Hotspot. David Holmes ------------ R?mi Forax said the following on 08/13/10 22:41: > Le 13/08/2010 05:28, Neal Gafter a ?crit : >> When a stack overflow exception suppresses another exception, I assume >> it's suppressed exception list will be set. But since there is only >> one such exception allocated by the VM, this will overwrite any data >> previously stored there. Will the VM be modified to comply with this >> specification by allocating a new stack-overflow exception each time? >> Same question for out-of-memory error. >> > > This problem already exists with jdk6. > This code change the stack trace of permanently allocated > OutOfMerroryError. > > public static void main(String[] args) { > Error last = null; > > for(int i=0; i<100; i++) { > try { > Object o = new int[Integer.MAX_VALUE]; > } catch (Error e) { > StackTraceElement[] stackTrace = e.getStackTrace(); > if (stackTrace != null && stackTrace.length>0 && > stackTrace[0].getLineNumber() == -3) { > e.printStackTrace(); > return; > } > > if (last == e) { > StackTraceElement element = new StackTraceElement("Foo", > "foo", null, -3); > e.setStackTrace(new StackTraceElement[]{element}); > } > last = e; > } > } > } > > > > To avoid that the VM has to clear the stacktrace when using the default > error: > in universe.cpp, in Universe::gen_out_of_memory_error: > > if (next < 0) { > // all preallocated errors have been used. > // return default > + java_lang_Throwable::clear_stacktrace(default_err); > return default_err; > } else { > > > And we should do the same for the field suppressed exceptions. > > R?mi > From David.Holmes at oracle.com Mon Aug 23 02:50:41 2010 From: David.Holmes at oracle.com (David Holmes) Date: Mon, 23 Aug 2010 19:50:41 +1000 Subject: Updated ARM Spec In-Reply-To: <4C7240FF.7020209@oracle.com> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C7240FF.7020209@oracle.com> Message-ID: <4C724471.9010606@oracle.com> I said the following on 08/23/10 19:35: > ... > The "suppressedException" array as I currently understand it would need > to be cleared, if the pre-allocated instances with no backtrace can > still contain "suppressedExceptions" - which I believe they can. I just realized however that clearing the suppressed-exception state is simply not an option as the same exception instance could be thrown concurrently in multiple threads. In short these shared immutable exception instances must remain immutable if they are to be shared. Hence they can not contain suppressed-exception information. David Holmes PS: I am not a subscriber to coin-dev. > Aside: StackOverflowException is created on demand, not pre-allocated, > in Hotspot. > > David Holmes > ------------ > > > R?mi Forax said the following on 08/13/10 22:41: >> Le 13/08/2010 05:28, Neal Gafter a ?crit : >>> When a stack overflow exception suppresses another exception, I assume >>> it's suppressed exception list will be set. But since there is only >>> one such exception allocated by the VM, this will overwrite any data >>> previously stored there. Will the VM be modified to comply with this >>> specification by allocating a new stack-overflow exception each time? >>> Same question for out-of-memory error. >>> >> >> This problem already exists with jdk6. >> This code change the stack trace of permanently allocated >> OutOfMerroryError. >> >> public static void main(String[] args) { >> Error last = null; >> >> for(int i=0; i<100; i++) { >> try { >> Object o = new int[Integer.MAX_VALUE]; >> } catch (Error e) { >> StackTraceElement[] stackTrace = e.getStackTrace(); >> if (stackTrace != null && stackTrace.length>0 && >> stackTrace[0].getLineNumber() == -3) { >> e.printStackTrace(); >> return; >> } >> >> if (last == e) { >> StackTraceElement element = new StackTraceElement("Foo", >> "foo", null, -3); >> e.setStackTrace(new StackTraceElement[]{element}); >> } >> last = e; >> } >> } >> } >> >> >> >> To avoid that the VM has to clear the stacktrace when using the >> default error: >> in universe.cpp, in Universe::gen_out_of_memory_error: >> >> if (next < 0) { >> // all preallocated errors have been used. >> // return default >> + java_lang_Throwable::clear_stacktrace(default_err); >> return default_err; >> } else { >> >> >> And we should do the same for the field suppressed exceptions. >> >> R?mi >> From David.Holmes at oracle.com Mon Aug 23 03:09:55 2010 From: David.Holmes at oracle.com (David Holmes) Date: Mon, 23 Aug 2010 20:09:55 +1000 Subject: Updated ARM Spec In-Reply-To: <4C72480B.3050104@univ-mlv.fr> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C7240FF.7020209@oracle.com> <4C724471.9010606@oracle.com> <4C72480B.3050104@univ-mlv.fr> Message-ID: <4C7248F3.4010200@oracle.com> R?mi Forax said the following on 08/23/10 20:06: > Le 23/08/2010 11:50, David Holmes a ?crit : >> I said the following on 08/23/10 19:35: >>> ... >>> The "suppressedException" array as I currently understand it would >>> need to be cleared, if the pre-allocated instances with no backtrace >>> can still contain "suppressedExceptions" - which I believe they can. >> >> I just realized however that clearing the suppressed-exception state >> is simply not an option as the same exception instance could be thrown >> concurrently in multiple threads. In short these shared immutable >> exception instances must remain immutable if they are to be shared. >> Hence they can not contain suppressed-exception information. >> >> David Holmes >> >> PS: I am not a subscriber to coin-dev. > > You can explicitly call setStackTrace() on a shared immutable exception, > hence there is a problem. > addSupressedExceptions() will have the same issue. I stand corrected. The Java side of the code couldn't care less about the VM level backtrace - it just installs a Java array. :( > I think the fix is to: > - silently discard the stack trace taken as argument of setStackTrace() > if the cause is 'null' (or not 'this') > - silently don't register suppressed-exceptions if cause is 'null' I think the Java code should be able to recognize a Throwable instance that should not allow these things to be set, and simply ignore the request. However that is a change in the spec for setStackTrace. Suppressed-exceptions could then be modelled like backtrace support - an optional facility generally used but ignored for the pre-allocated immutable instances. David > R?mi > >> >>> Aside: StackOverflowException is created on demand, not >>> pre-allocated, in Hotspot. >>> >>> David Holmes >>> ------------ >>> >>> >>> R?mi Forax said the following on 08/13/10 22:41: >>>> Le 13/08/2010 05:28, Neal Gafter a ?crit : >>>>> When a stack overflow exception suppresses another exception, I assume >>>>> it's suppressed exception list will be set. But since there is only >>>>> one such exception allocated by the VM, this will overwrite any data >>>>> previously stored there. Will the VM be modified to comply with this >>>>> specification by allocating a new stack-overflow exception each time? >>>>> Same question for out-of-memory error. >>>> >>>> This problem already exists with jdk6. >>>> This code change the stack trace of permanently allocated >>>> OutOfMerroryError. >>>> >>>> public static void main(String[] args) { >>>> Error last = null; >>>> >>>> for(int i=0; i<100; i++) { >>>> try { >>>> Object o = new int[Integer.MAX_VALUE]; >>>> } catch (Error e) { >>>> StackTraceElement[] stackTrace = e.getStackTrace(); >>>> if (stackTrace != null && stackTrace.length>0 && >>>> stackTrace[0].getLineNumber() == -3) { >>>> e.printStackTrace(); >>>> return; >>>> } >>>> >>>> if (last == e) { >>>> StackTraceElement element = new StackTraceElement("Foo", >>>> "foo", null, -3); >>>> e.setStackTrace(new StackTraceElement[]{element}); >>>> } >>>> last = e; >>>> } >>>> } >>>> } >>>> >>>> >>>> >>>> To avoid that the VM has to clear the stacktrace when using the >>>> default error: >>>> in universe.cpp, in Universe::gen_out_of_memory_error: >>>> >>>> if (next < 0) { >>>> // all preallocated errors have been used. >>>> // return default >>>> + java_lang_Throwable::clear_stacktrace(default_err); >>>> return default_err; >>>> } else { >>>> >>>> >>>> And we should do the same for the field suppressed exceptions. >>>> >>>> R?mi >>>> > From David.Holmes at oracle.com Mon Aug 23 03:29:50 2010 From: David.Holmes at oracle.com (David Holmes) Date: Mon, 23 Aug 2010 20:29:50 +1000 Subject: Updated ARM Spec In-Reply-To: <4C724C26.6040709@univ-mlv.fr> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C7240FF.7020209@oracle.com> <4C724471.9010606@oracle.com> <4C72480B.3050104@univ-mlv.fr> <4C7248F3.4010200@oracle.com> <4C724C26.6040709@univ-mlv.fr> Message-ID: <4C724D9E.8030100@oracle.com> R?mi Forax said the following on 08/23/10 20:23: > Le 23/08/2010 12:09, David Holmes a ?crit : >> R?mi Forax said the following on 08/23/10 20:06: >>> You can explicitly call setStackTrace() on a shared immutable >>> exception, hence there is a problem. >>> addSupressedExceptions() will have the same issue. >> >> I stand corrected. The Java side of the code couldn't care less about >> the VM level backtrace - it just installs a Java array. :( >> >>> I think the fix is to: >>> - silently discard the stack trace taken as argument of >>> setStackTrace() if the cause is 'null' (or not 'this') >>> - silently don't register suppressed-exceptions if cause is 'null' >> >> I think the Java code should be able to recognize a Throwable instance >> that should not allow these things to be set, and simply ignore the >> request. However that is a change in the spec for setStackTrace. > > Yes, setStackTrace() can 'not succeed'. > And the way to recognize such Throwable instance is to check is the > field 'cause' is null. Except if someone invokes setCause(null). By the way, probing further, the non-OOME shared pre-allocated instances do not guard themselves against fillInStackTrace being invoked upon them. That is arguably an additional bug. I say arguably simply because in the circumstances under which those other exceptions are thrown, having a misleading stacktrace is probably the least of the application's worries. David >> Suppressed-exceptions could then be modelled like backtrace support - >> an optional facility generally used but ignored for the pre-allocated >> immutable instances. > > Yes, and the spec must be also updated accordingly. > >> >> David > > R?mi From joe.darcy at oracle.com Mon Aug 23 12:45:19 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Mon, 23 Aug 2010 12:45:19 -0700 Subject: Updated ARM Spec In-Reply-To: <4C727018.5090409@univ-mlv.fr> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C7240FF.7020209@oracle.com> <4C724471.9010606@oracle.com> <4C72480B.3050104@univ-mlv.fr> <4C7248F3.4010200@oracle.com> <4C724C26.6040709@univ-mlv.fr> <4C724D9E.8030100@oracle.com> <4C727018.5090409@univ-mlv.fr> Message-ID: <4C72CFCF.5060904@oracle.com> R?mi Forax wrote: > Le 23/08/2010 12:29, David Holmes a ?crit : > >> R?mi Forax said the following on 08/23/10 20:23: >> >>> Le 23/08/2010 12:09, David Holmes a ?crit : >>> >>>> R?mi Forax said the following on 08/23/10 20:06: >>>> >>>>> You can explicitly call setStackTrace() on a shared immutable >>>>> exception, hence there is a problem. >>>>> addSupressedExceptions() will have the same issue. >>>>> >>>> I stand corrected. The Java side of the code couldn't care less >>>> about the VM level backtrace - it just installs a Java array. :( >>>> >>>> >>>>> I think the fix is to: >>>>> - silently discard the stack trace taken as argument of >>>>> setStackTrace() if the cause is 'null' (or not 'this') >>>>> - silently don't register suppressed-exceptions if cause is 'null' >>>>> >>>> I think the Java code should be able to recognize a Throwable >>>> instance that should not allow these things to be set, and simply >>>> ignore the request. However that is a change in the spec for >>>> setStackTrace. >>>> >>> Yes, setStackTrace() can 'not succeed'. >>> And the way to recognize such Throwable instance is to check is the >>> field 'cause' is null. >>> >> Except if someone invokes setCause(null). >> > > setCause(null) should set the field cause to this. > For Throwable(null) and Throwable(message, null), null should also be > escaped. > > The other solution is to use the field suppressedExceptions with the > invariant that if > it's null, it's an immutable shared exception. > > >> By the way, probing further, the non-OOME shared pre-allocated >> instances do not guard themselves against fillInStackTrace being >> invoked upon them. That is arguably an additional bug. I say arguably >> simply because in the circumstances under which those other exceptions >> are thrown, having a misleading stacktrace is probably the least of >> the application's worries. >> > > yes, you right. > > To recap, Throwable objects have several pieces of mutable state: * the cause; this is a write-at-most-once value that can be set set via a constructor, like Throwable(Throwable cause) or Throwable(String message, Throwable cause), or set after construction via the Throwable.initCause method. (Setting the cause to null prevents future assignment.) * the stack trace; set by fillInStackTrace() or setStackTrace(StackTraceElement[] stackTrace) -- there doesn't seem to be any API prohibition against setting the stack trace multiple times * suppressed exceptions : new functionality added to support try-with-resources statements/ARM blocks. Modified via calling addSuppressedException Focusing just on suppressed exceptions, to support the JVM reusing exception objects, the Throwable API should have some idiom to indicate suppressed exception information should *not* be recorded. Logically this amount to having the list of exceptions be a zero-length list which just discards adds. I'm hesitant to overload a null cause with discarding suppressed exceptions too. Instead, I propose the following: * a null value of the suppressedException field indicates addSuppressedException is a no-op. * the suppressedException field is initialized to point to a sentinel list in Throwable, something non-null that can be used for == checks. With this protocol, the "raw" Throwable objects created by the JVM get the addSuppressedException is a no-op behavior for free. * if the first call to addSuppressedException has this as an argument, the suppressedException field is null-ed; otherwise, a list is appended to as usual. Comments? -Joe From David.Holmes at oracle.com Mon Aug 23 17:17:52 2010 From: David.Holmes at oracle.com (David Holmes) Date: Tue, 24 Aug 2010 10:17:52 +1000 Subject: Updated ARM Spec In-Reply-To: <4C72CFCF.5060904@oracle.com> References: <4C3F8142.2030203@oracle.com> <4C5AE91C.1070908@oracle.com> <4C653D7B.6020001@univ-mlv.fr> <4C7240FF.7020209@oracle.com> <4C724471.9010606@oracle.com> <4C72480B.3050104@univ-mlv.fr> <4C7248F3.4010200@oracle.com> <4C724C26.6040709@univ-mlv.fr> <4C724D9E.8030100@oracle.com> <4C727018.5090409@univ-mlv.fr> <4C72CFCF.5060904@oracle.com> Message-ID: <4C730FB0.6030100@oracle.com> Joe Darcy said the following on 08/24/10 05:45: > To recap, Throwable objects have several pieces of mutable state: > > * the cause; this is a write-at-most-once value that can be set set via > a constructor, like Throwable(Throwable cause) or Throwable(String > message, Throwable cause), or set after construction via the > Throwable.initCause method. (Setting the cause to null prevents future > assignment.) > > * the stack trace; set by fillInStackTrace() or > setStackTrace(StackTraceElement[] stackTrace) -- there doesn't seem to > be any API prohibition against setting the stack trace multiple times But note that the VM implements fillInStackTrace and can ignore the request, while setStackTrace is pure Java. > * suppressed exceptions : new functionality added to support > try-with-resources statements/ARM blocks. Modified via calling > addSuppressedException > > Focusing just on suppressed exceptions, to support the JVM reusing > exception objects, the Throwable API should have some idiom to indicate > suppressed exception information should *not* be recorded. Logically > this amount to having the list of exceptions be a zero-length list which > just discards adds. > > I'm hesitant to overload a null cause with discarding suppressed > exceptions too. Instead, I propose the following: > > * a null value of the suppressedException field indicates > addSuppressedException is a no-op. > > * the suppressedException field is initialized to point to a sentinel > list in Throwable, something non-null that can be used for == checks. > With this protocol, the "raw" Throwable objects created by the JVM get > the addSuppressedException is a no-op behavior for free. > > * if the first call to addSuppressedException has this as an argument, > the suppressedException field is null-ed; otherwise, a list is appended > to as usual. > > Comments? It seems to me, inline with what has been written, that Throwable should adopt the overall approach that for each of the cause, stacktrace and suppressedExceptions fields: - null indicates that these fields can not be modified (and is the default we get from the instances pre-allocated in the VM) - the default initialization, via the constructor, is always a non-NULL sentinel value This requires several changes to the existing method specifications. David From David.Holmes at oracle.com Mon Aug 23 21:46:40 2010 From: David.Holmes at oracle.com (David Holmes) Date: Tue, 24 Aug 2010 14:46:40 +1000 Subject: suppressedException semantics Message-ID: <4C734EB0.7070103@oracle.com> I realize that I am late to the game here but reading Joe's latest ARM proposal (and having looked into the issues with pre-allocated exceptions) I find that the semantics of suppressed exceptions for try-with-resources are actually the opposite to what I initially thought. Taking regular Java as it stands, given: try { throw new A(); } finally { throw new B(); } the try-finally will always complete by throwing B and the fact that A occurred has been lost. Exception B has suppressed exception A in this case. So I thought that the addition of suppressedExceptions was a way for B to indicate that it has suppressed A. This could be considered a general language extension independent of try-with-resources: it is simply a way for exceptions that would be lost to be "chained" to the exception that replaced them. (And in such an extension I probably would not make addSuppressedException a generally available API.) What try-with-resources proposes is actually suppressing B (when it comes from an AutoCloseable) and propagating A. I find this somewhat confusing, especially when the argument of whether to suppress only Exception but not Error etc is taken into account. It is not apparent to me why the exception from the try block is more important than the exception from the finally block? As long as A can be found from B does it matter which is actually thrown? I would suggest that the try-with-resources code transformation would be a lot simpler if it did not change the exception that would naturally be thrown from the finally clause. It would also make it a moot point whether to distinguish Error from Exception etc. I just can't help but think that this is more complex than it needs to be. And at the same time that the "suppressed exception" mechanism is not as generally useful as it could be. And yes I've just donned my flak-jacket ;-) Cheers, David Holmes From mcnepp02 at googlemail.com Tue Aug 24 02:27:20 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Tue, 24 Aug 2010 09:27:20 +0000 Subject: trying out the prototype Message-ID: Hello, first of all I have to say that as a long-time advocate of some kind of ARM in Java I'm thrilled to finally see it in action! I've toyed with the latest snapshot and have 2 remarks: 1. If you initialize a Resource that can only throw on close(), you get a compiler error that might be confusing because the automatic invocation of close() is invisible to the person writing the code. Here's a not-so-useful example that nevertheless exhibits the aforementioned behaviour: try (Reader rdr = new StringReader("Some text")) { } 2. If you use multiple Resources, an exception thrown by one of them will suppress exceptions thrown by the 'close()' invocation of others. While I can see some sense in suppressing exceptions from 'close()' of the same instance, I cannot see why this reasoning should apply to other instances. (I guess this forms a case against the try-with-multiple-resources statement in general. The list of semicolon-delimited declarations enclosed by parentheses looks weird, anyway ;-) Here's an example: class ThrowsOnRead extends Reader { public int read(char[] cbuf, int off, int len) throws IOException { throw new IOException(); } @Override public void close() throws IOException { } } class ThrowsOnClose extends Reader { public void close() throws IOException { throw new IOException(); } public int read(char[] cbuf, int off, int len) throws IOException { return 0; } } public class TestAutoClose { public static void main(String[] args) throws IOException { try(Reader rdr1 = new ThrowsOnRead(); Reader rdr2 = new ThrowsOnClose()) { rdr1.read(); // Why is this exception more important than the one thrown by rdr2.close() ? } } } From reinier at zwitserloot.com Tue Aug 24 03:20:59 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 24 Aug 2010 12:20:59 +0200 Subject: suppressedException semantics In-Reply-To: <4C734EB0.7070103@oracle.com> References: <4C734EB0.7070103@oracle.com> Message-ID: I get the feeling Paul Benedict is saying the opposite of what David Holmes is saying, which is a bit confusing. Paul: David is suggesting that the original exception should NOT be thrown in the new trywith construct, to mirror the behaviour of what happens in existing try/finally blocks. David: The idea behind throwing the original and tacking on any further exceptions as suppressed ones is because the original one is simply better. If for example a network connection fails due to for example a broken pipe, the original exception will say so. If I then close a bunch of resources related to the socket, all sorts of further exceptions will fall out, mostly based around the notion that the entire socket has become invalidated. These may no longer state the original reason for the failure of the socket (broken pipe). Also, the point at which the socket broke, is when the original exception occurred. Its stack trace is the best one, of all traces of all thrown exceptions, in that its closest to the actual state of the stack at the time the problem occurred. Of course, tweaking how standard try/finally works where the finally block throws its own exception is not possible, because that would break backwards compatibility. There is indeed a slight inconsistency in having trywith work differently from try/finally, but in retrospect, if suppressedexceptions had been available from oak 1.0, having the exception in the try block be 'more important' than further exceptions is clearly the right way to go. Thus, where we can switch to the better option without breaking backwards compatibility, we do, and where we can't, we don't. Seems reasonable to me. --Reinier Zwitserloot On Tue, Aug 24, 2010 at 6:46 AM, David Holmes wrote: > I realize that I am late to the game here but reading Joe's latest ARM > proposal (and having looked into the issues with pre-allocated > exceptions) I find that the semantics of suppressed exceptions for > try-with-resources are actually the opposite to what I initially thought. > > Taking regular Java as it stands, given: > > try { > throw new A(); > } > finally { > throw new B(); > } > > the try-finally will always complete by throwing B and the fact that A > occurred has been lost. Exception B has suppressed exception A in this > case. So I thought that the addition of suppressedExceptions was a way > for B to indicate that it has suppressed A. This could be considered a > general language extension independent of try-with-resources: it is > simply a way for exceptions that would be lost to be "chained" to the > exception that replaced them. (And in such an extension I probably would > not make addSuppressedException a generally available API.) > > What try-with-resources proposes is actually suppressing B (when it > comes from an AutoCloseable) and propagating A. I find this somewhat > confusing, especially when the argument of whether to suppress only > Exception but not Error etc is taken into account. It is not apparent to > me why the exception from the try block is more important than the > exception from the finally block? As long as A can be found from B does > it matter which is actually thrown? I would suggest that the > try-with-resources code transformation would be a lot simpler if it did > not change the exception that would naturally be thrown from the finally > clause. It would also make it a moot point whether to distinguish Error > from Exception etc. > > I just can't help but think that this is more complex than it needs to > be. And at the same time that the "suppressed exception" mechanism is > not as generally useful as it could be. > > And yes I've just donned my flak-jacket ;-) > > Cheers, > David Holmes > > From David.Holmes at oracle.com Tue Aug 24 04:10:53 2010 From: David.Holmes at oracle.com (David Holmes) Date: Tue, 24 Aug 2010 21:10:53 +1000 Subject: suppressedException semantics In-Reply-To: References: <4C734EB0.7070103@oracle.com> Message-ID: <4C73A8BD.3090003@oracle.com> Reinier Zwitserloot said the following on 08/24/10 20:20: > I get the feeling Paul Benedict is saying the opposite of what David > Holmes is saying, which is a bit confusing. Paul: David is suggesting > that the original exception should NOT be thrown in the new trywith > construct, to mirror the behaviour of what happens in existing > try/finally blocks. I haven't seen Paul's mail as I just started subscribing. Sorry if I seem to be changing the tack of an ongoing discussion. These are just my views. > David: The idea behind throwing the original and tacking on any > further exceptions as suppressed ones is because the original one is > simply better. If for example a network connection fails due to for > example a broken pipe, the original exception will say so. If I then > close a bunch of resources related to the socket, all sorts of > further exceptions will fall out, mostly based around the notion that > the entire socket has become invalidated. These may no longer state > the original reason for the failure of the socket (broken pipe). > Also, the point at which the socket broke, is when the original > exception occurred. Its stack trace is the best one, of all traces of > all thrown exceptions, in that its closest to the actual state of the > stack at the time the problem occurred. But does it really matter as long as the less-better exception reports the original better one? This would be just like the way the "cause" works today - the final exception is not the key one, but the one that caused it. I see the trywith proposal as running counter to try-finally and to the current "caused-by" semantics. As long as the exception you catch will print or otherwise make available the chain of exceptions, then you have what you need. In which case a simpler mechanism that is consistent with existing language and API features is preferable in my view. > Of course, tweaking how standard try/finally works where the finally > block throws its own exception is not possible, because that would > break backwards compatibility. There is indeed a slight inconsistency > in having trywith work differently from try/finally, but in > retrospect, if suppressedexceptions had been available from oak 1.0, > having the exception in the try block be 'more important' than > further exceptions is clearly the right way to go. Thus, where we can > switch to the better option without breaking backwards compatibility, > we do, and where we can't, we don't. Seems reasonable to me. Well I disagree that the exception in the try block is necessarily more important than the one in the finally block. The flaw in 1.0 was that you lost the first exception. Cheers, David > > --Reinier Zwitserloot > > > > On Tue, Aug 24, 2010 at 6:46 AM, David Holmes > > wrote: > > I realize that I am late to the game here but reading Joe's latest > ARM proposal (and having looked into the issues with pre-allocated > exceptions) I find that the semantics of suppressed exceptions for > try-with-resources are actually the opposite to what I initially > thought. > > Taking regular Java as it stands, given: > > try { throw new A(); } finally { throw new B(); } > > the try-finally will always complete by throwing B and the fact that > A occurred has been lost. Exception B has suppressed exception A in > this case. So I thought that the addition of suppressedExceptions was > a way for B to indicate that it has suppressed A. This could be > considered a general language extension independent of > try-with-resources: it is simply a way for exceptions that would be > lost to be "chained" to the exception that replaced them. (And in > such an extension I probably would not make addSuppressedException a > generally available API.) > > What try-with-resources proposes is actually suppressing B (when it > comes from an AutoCloseable) and propagating A. I find this somewhat > confusing, especially when the argument of whether to suppress only > Exception but not Error etc is taken into account. It is not apparent > to me why the exception from the try block is more important than the > exception from the finally block? As long as A can be found from B > does it matter which is actually thrown? I would suggest that the > try-with-resources code transformation would be a lot simpler if it > did not change the exception that would naturally be thrown from the > finally clause. It would also make it a moot point whether to > distinguish Error from Exception etc. > > I just can't help but think that this is more complex than it needs > to be. And at the same time that the "suppressed exception" mechanism > is not as generally useful as it could be. > > And yes I've just donned my flak-jacket ;-) > > Cheers, David Holmes > > From David.Holmes at oracle.com Tue Aug 24 04:14:10 2010 From: David.Holmes at oracle.com (David Holmes) Date: Tue, 24 Aug 2010 21:14:10 +1000 Subject: trying out the prototype In-Reply-To: References: Message-ID: <4C73A982.3060400@oracle.com> Gernot Neppert said the following on 08/24/10 19:27: > 2. If you use multiple Resources, an exception thrown by one of them > will suppress exceptions thrown by the 'close()' invocation of others. > While I can see some sense in suppressing exceptions from 'close()' of > the same instance, I cannot see why this reasoning should apply to > other instances. > (I guess this forms a case against the try-with-multiple-resources > statement in general. The list of semicolon-delimited declarations > enclosed by parentheses looks weird, anyway ;-) I tend to agree the syntax is awkward and far less readable than simply nesting the try-with statements. David Holmes > Here's an example: > > class ThrowsOnRead extends Reader > { > public int read(char[] cbuf, int off, int len) throws IOException > { > throw new IOException(); > } > > @Override > public void close() throws IOException > { > > } > } > > class ThrowsOnClose extends Reader > { > public void close() throws IOException > { > throw new IOException(); > } > > public int read(char[] cbuf, int off, int len) throws IOException > { > return 0; > } > } > > > > public class TestAutoClose { > > public static void main(String[] args) throws IOException { > try(Reader rdr1 = new ThrowsOnRead(); Reader rdr2 = new ThrowsOnClose()) > { > rdr1.read(); // Why is this exception more important than the > one thrown by rdr2.close() ? > } > } > } > From mcnepp02 at googlemail.com Tue Aug 24 05:29:05 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Tue, 24 Aug 2010 12:29:05 +0000 Subject: suppressedException semantics In-Reply-To: <4C73A8BD.3090003@oracle.com> References: <4C734EB0.7070103@oracle.com> <4C73A8BD.3090003@oracle.com> Message-ID: > Well I disagree that the exception in the try block is necessarily more > important than the one in the finally block. It might not be more important, but it might be the only one that you can spot by looking at the code: try(Reader reader = new FileReader("contents.txt")) { char[] buf = new char[1000]; int read; while(0 < (read = reader.read(buf))) { // Do something } } Wouldn't you want the above block to re-throw exceptions from the constructor or from 'read', rather than from an 'invisible' exception source? (See also my other post suggesting that the compiler might be more helpful in pointing at 'hidden' exception sources) From reinier at zwitserloot.com Tue Aug 24 05:42:49 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 24 Aug 2010 14:42:49 +0200 Subject: suppressedException semantics In-Reply-To: <4C73A8BD.3090003@oracle.com> References: <4C734EB0.7070103@oracle.com> <4C73A8BD.3090003@oracle.com> Message-ID: Yes, it really matters. No current tools are capable of reporting suppressed exceptions. Between the causality chain and each exception in it having suppressed exceptions, with all of THOSE potentially also having a causality chain and further suppressed exceptions, a single problem can result in many tens of stack traces. Making sure there is such a thing as the primary trace amongst the set, and making sure that the odds are good this one exception trace is more useful than the others, is obviously (to me, anyway), a worthwhile endeavour, and is certainly worth a little inconsistency. --Reinier Zwitserloot On Tue, Aug 24, 2010 at 1:10 PM, David Holmes wrote: > Reinier Zwitserloot said the following on 08/24/10 20:20: > > I get the feeling Paul Benedict is saying the opposite of what David >> Holmes is saying, which is a bit confusing. Paul: David is suggesting >> that the original exception should NOT be thrown in the new trywith >> construct, to mirror the behaviour of what happens in existing >> try/finally blocks. >> > > I haven't seen Paul's mail as I just started subscribing. Sorry if I seem > to be changing the tack of an ongoing discussion. These are just my views. > > > David: The idea behind throwing the original and tacking on any >> further exceptions as suppressed ones is because the original one is >> simply better. If for example a network connection fails due to for >> example a broken pipe, the original exception will say so. If I then >> close a bunch of resources related to the socket, all sorts of >> further exceptions will fall out, mostly based around the notion that >> the entire socket has become invalidated. These may no longer state >> the original reason for the failure of the socket (broken pipe). >> Also, the point at which the socket broke, is when the original >> exception occurred. Its stack trace is the best one, of all traces of >> all thrown exceptions, in that its closest to the actual state of the >> stack at the time the problem occurred. >> > > But does it really matter as long as the less-better exception reports the > original better one? This would be just like the way the "cause" works today > - the final exception is not the key one, but the one that caused it. I see > the trywith proposal as running counter to try-finally and to the current > "caused-by" semantics. As long as the exception you catch will print or > otherwise make available the chain of exceptions, then you have what you > need. In which case a simpler mechanism that is consistent with existing > language and API features is preferable in my view. > > > Of course, tweaking how standard try/finally works where the finally >> block throws its own exception is not possible, because that would >> break backwards compatibility. There is indeed a slight inconsistency >> in having trywith work differently from try/finally, but in >> retrospect, if suppressedexceptions had been available from oak 1.0, >> having the exception in the try block be 'more important' than >> further exceptions is clearly the right way to go. Thus, where we can >> switch to the better option without breaking backwards compatibility, >> we do, and where we can't, we don't. Seems reasonable to me. >> > > Well I disagree that the exception in the try block is necessarily more > important than the one in the finally block. The flaw in 1.0 was that > you lost the first exception. > > Cheers, > David > >> >> --Reinier Zwitserloot >> >> >> >> On Tue, Aug 24, 2010 at 6:46 AM, David Holmes >> > wrote: >> >> I realize that I am late to the game here but reading Joe's latest >> ARM proposal (and having looked into the issues with pre-allocated >> exceptions) I find that the semantics of suppressed exceptions for >> try-with-resources are actually the opposite to what I initially thought. >> >> Taking regular Java as it stands, given: >> >> try { throw new A(); } finally { throw new B(); } >> >> the try-finally will always complete by throwing B and the fact that >> A occurred has been lost. Exception B has suppressed exception A in >> this case. So I thought that the addition of suppressedExceptions was >> a way for B to indicate that it has suppressed A. This could be >> considered a general language extension independent of >> try-with-resources: it is simply a way for exceptions that would be >> lost to be "chained" to the exception that replaced them. (And in >> such an extension I probably would not make addSuppressedException a >> generally available API.) >> >> What try-with-resources proposes is actually suppressing B (when it comes >> from an AutoCloseable) and propagating A. I find this somewhat confusing, >> especially when the argument of whether to suppress only Exception but not >> Error etc is taken into account. It is not apparent >> to me why the exception from the try block is more important than the >> exception from the finally block? As long as A can be found from B >> does it matter which is actually thrown? I would suggest that the >> try-with-resources code transformation would be a lot simpler if it >> did not change the exception that would naturally be thrown from the >> finally clause. It would also make it a moot point whether to >> distinguish Error from Exception etc. >> >> I just can't help but think that this is more complex than it needs >> to be. And at the same time that the "suppressed exception" mechanism >> is not as generally useful as it could be. >> >> And yes I've just donned my flak-jacket ;-) >> >> Cheers, David Holmes >> >> >> From scolebourne at joda.org Tue Aug 24 06:07:45 2010 From: scolebourne at joda.org (Stephen Colebourne) Date: Tue, 24 Aug 2010 14:07:45 +0100 Subject: trying out the prototype In-Reply-To: <4C73A982.3060400@oracle.com> References: <4C73A982.3060400@oracle.com> Message-ID: On 24 August 2010 12:14, David Holmes wrote: >> (I guess this forms a case against the try-with-multiple-resources >> statement in general. The list of semicolon-delimited declarations >> enclosed by parentheses looks weird, anyway ;-) > > I tend to agree the syntax is awkward and far less readable than simply > nesting the try-with statements. Overall, I think the semicolon, multi-resource, aspect is more complex than the benefits it gives. Clearer code results from nesting the statements. Stephen From serge.boulay at gmail.com Tue Aug 24 06:40:52 2010 From: serge.boulay at gmail.com (Serge Boulay) Date: Tue, 24 Aug 2010 09:40:52 -0400 Subject: trying out the prototype In-Reply-To: References: <4C73A982.3060400@oracle.com> Message-ID: The "using" block in c# only allows one resource unless the resources are of the same type. To use multiple resources they are nested or stacked using (StreamWriter w1 = File.CreateText("W1")) using (StreamWriter w2 = File.CreateText("W2")) { // code here } instead of using (StreamWriter w1 = File.CreateText("W1")) { using (StreamWriter w2 = File.CreateText("W2")) { // code here } } Depending on the number of resources, the "using" block nesting can quickly get out of hand. On 8/24/10, Stephen Colebourne wrote: > > On 24 August 2010 12:14, David Holmes wrote: > >> (I guess this forms a case against the try-with-multiple-resources > >> statement in general. The list of semicolon-delimited declarations > >> enclosed by parentheses looks weird, anyway ;-) > > > > I tend to agree the syntax is awkward and far less readable than simply > > nesting the try-with statements. > > Overall, I think the semicolon, multi-resource, aspect is more complex > than the benefits it gives. Clearer code results from nesting the > statements. > > Stephen > > From pbenedict at apache.org Tue Aug 24 06:50:06 2010 From: pbenedict at apache.org (Paul Benedict) Date: Tue, 24 Aug 2010 08:50:06 -0500 Subject: suppressedException semantics In-Reply-To: References: <4C734EB0.7070103@oracle.com> <4C73A8BD.3090003@oracle.com> Message-ID: To Dave's example: try { throw new A(); } finally { throw new B(); } I think he wants to automatically chain/suppress exceptions when an exception is live on the stack. Here, B would be thrown and the JVM would automatically add the A exception as a suppressed exception. Paul From zhong.j.yu at gmail.com Tue Aug 24 11:37:23 2010 From: zhong.j.yu at gmail.com (Zhong Yu) Date: Tue, 24 Aug 2010 13:37:23 -0500 Subject: trying out the prototype In-Reply-To: References: <4C73A982.3060400@oracle.com> Message-ID: How about this: // any block { int c; try FileReader reader = new FileReader( source ); try FileWriter writer = new FileWriter( target ); while( (c = reader.read()) != -1 ) writer.write(c); } The [try ResourceSpecification] statement can appear anywhere in a block. When the enclosing block completes, close() methods are invoked. It's almost as if we have destructors public void copy(File source, File target) throws IOException { int c; try FileReader reader = new FileReader( source ); try FileWriter writer = new FileWriter( target ); while( (c = reader.read()) != -1 ) writer.write(c); } // reader and writer will be closed upon method completion Since we piggyback it on an existing block, we can avoid one indentation, and making code more readable. Compatibility isn't broken, the new behavior of the block only arise if the new type of statement appears inside. The "try" keyword probably sounds unnatural for this purpose. Maybe we can use some other keyword or symbol. IDE should warn when it appears that an auto-closeable resource is not, but should be, initialized this way. Note, the auto-close behavior stays the same even if the enclosing block is a try block try { int c; try FileReader reader = new FileReader( source ); try FileWriter writer = new FileWriter( target ); while( (c = reader.read()) != -1 ) writer.write(c); } catch(IOException e) { // reader and writer already closed! } Zhong Yu On Tue, Aug 24, 2010 at 8:40 AM, Serge Boulay wrote: > The "using" block in c# only allows one resource unless the resources are of > the same type. To use multiple resources they are nested or stacked > > using (StreamWriter w1 = File.CreateText("W1")) > using (StreamWriter w2 = File.CreateText("W2")) > { > ? ? ?// code here > } > > instead of > > using (StreamWriter w1 = File.CreateText("W1")) > ?{ > ? ? ?using (StreamWriter w2 = File.CreateText("W2")) > ? ? ?{ > ? ? ? ? ?// code here > ? ? ?} > ? } > > Depending on the number of resources, the "using" block nesting can quickly > get out of hand. > > > > > > On 8/24/10, Stephen Colebourne wrote: >> >> On 24 August 2010 12:14, David Holmes wrote: >> >> (I guess this forms a case against the try-with-multiple-resources >> >> statement in general. The list of semicolon-delimited declarations >> >> enclosed by parentheses looks weird, anyway ;-) >> > >> > I tend to agree the syntax is awkward and far less readable than simply >> > nesting the try-with statements. >> >> Overall, I think the semicolon, multi-resource, aspect is more complex >> than the benefits it gives. Clearer code results from nesting the >> statements. >> >> Stephen >> >> > > From joe.darcy at oracle.com Tue Aug 24 11:41:20 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Tue, 24 Aug 2010 11:41:20 -0700 Subject: suppressedException semantics In-Reply-To: <4C734EB0.7070103@oracle.com> References: <4C734EB0.7070103@oracle.com> Message-ID: <4C741250.9010702@oracle.com> David Holmes wrote: > I realize that I am late to the game here but reading Joe's latest ARM > proposal (and having looked into the issues with pre-allocated > exceptions) I find that the semantics of suppressed exceptions for > try-with-resources are actually the opposite to what I initially thought. > > Taking regular Java as it stands, given: > > try { > throw new A(); > } > finally { > throw new B(); > } > > the try-finally will always complete by throwing B and the fact that A > occurred has been lost. Exception B has suppressed exception A in this > case. Just to be clear on the proposal, in the code example two exceptions are thrown and only one, B, propagates out. All information about the existence of A is lost. The proposal could, but does *not*, change the semantics of try-finally *without* a resource so that A was listed as a suppressed exception of B. > So I thought that the addition of suppressedExceptions was a way > for B to indicate that it has suppressed A. This could be considered a > general language extension independent of try-with-resources: it is > simply a way for exceptions that would be lost to be "chained" to the > exception that replaced them. (And in such an extension I probably would > not make addSuppressedException a generally available API.) > > What try-with-resources proposes is actually suppressing B (when it > comes from an AutoCloseable) and propagating A. Yes, the current semantics of try-with-resources is that the first exception thrown wins in terms of getting propagated out. This is opposite to the try-finally case above. > I find this somewhat > confusing, especially when the argument of whether to suppress only > Exception but not Error etc is taken into account. It is not apparent to > me why the exception from the try block is more important than the > exception from the finally block? In my estimation, the first exception thrown is the one most likely to be information of what exactly went wrong as opposed to just being a cascading consequence of prior exceptions/problems. > As long as A can be found from B does > it matter which is actually thrown? I would suggest that the > try-with-resources code transformation would be a lot simpler if it did > not change the exception that would naturally be thrown from the finally > clause. It would also make it a moot point whether to distinguish Error > from Exception etc. > > I just can't help but think that this is more complex than it needs to > be. And at the same time that the "suppressed exception" mechanism is > not as generally useful as it could be. > > And yes I've just donned my flak-jacket ;-) > > Cheers, > David Holmes > > First-thrown-exception wins and last-thrown-exception wins are two simple and predictable polices toward handling suppression. I find "I'm a worse problem then you" logic at each point along the way unappealing since it would be hard to know what throwable would eventually come out. Of two errors, which is worse? Is a checked exception worse than a runtime exception? Is a non-error, non-java.lang.Exception Throwable worse than an Error? ... -Joe From joe.darcy at oracle.com Tue Aug 24 11:45:53 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Tue, 24 Aug 2010 11:45:53 -0700 Subject: trying out the prototype In-Reply-To: References: <4C73A982.3060400@oracle.com> Message-ID: <4C741361.1070505@oracle.com> Stephen Colebourne wrote: > On 24 August 2010 12:14, David Holmes wrote: > >>> (I guess this forms a case against the try-with-multiple-resources >>> statement in general. The list of semicolon-delimited declarations >>> enclosed by parentheses looks weird, anyway ;-) >>> >> I tend to agree the syntax is awkward and far less readable than simply >> nesting the try-with statements. >> > > Overall, I think the semicolon, multi-resource, aspect is more complex > than the benefits it gives. Clearer code results from nesting the > statements. > > I disagree based on my experiences developing tests for the feature. Compare "testCreateFailure" with "testCreateFailureNested" in http://hg.openjdk.java.net/jdk7/jdk7/langtools/file/2c1c657f69a4/test/tools/javac/TryWithResources/TwrTests.java -Joe From joe.darcy at oracle.com Tue Aug 24 11:50:10 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Tue, 24 Aug 2010 11:50:10 -0700 Subject: trying out the prototype In-Reply-To: References: Message-ID: <4C741462.7060908@oracle.com> Gernot Neppert wrote: > Hello, > > first of all I have to say that as a long-time advocate of some kind > of ARM in Java I'm thrilled to finally see it in action! > > I've toyed with the latest snapshot and have 2 remarks: > > 1. If you initialize a Resource that can only throw on close(), you > get a compiler error that might be confusing because the automatic > invocation of close() is invisible to the person writing the code. > Here's a not-so-useful example that nevertheless exhibits the > aforementioned behaviour: > > try (Reader rdr = new StringReader("Some text")) > { > } > > 2. If you use multiple Resources, an exception thrown by one of them > will suppress exceptions thrown by the 'close()' invocation of others. > While I can see some sense in suppressing exceptions from 'close()' of > the same instance, I cannot see why this reasoning should apply to > other instances. > (I guess this forms a case against the try-with-multiple-resources > statement in general. The list of semicolon-delimited declarations > enclosed by parentheses looks weird, anyway ;-) > Here's an example: > With N resources, there are possibly N+1 exceptions that can come out of the try-with-resources statement, 1 from the block itself and 1 from each of the close calls. Only one of those exceptions can be the one which gets propagated out of the block. As covered in the other recent thread, the first exception thrown is estimated to be the most informative one about what actually went wrong. -Joe From joe.darcy at oracle.com Tue Aug 24 11:55:21 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Tue, 24 Aug 2010 11:55:21 -0700 Subject: trying out the prototype In-Reply-To: References: <4C73A982.3060400@oracle.com> Message-ID: <4C741599.6000702@oracle.com> Zhong Yu wrote: > How about this: > No. Trying out the prototype is an invitation to give feedback on the prototype. It is not an invitation to start designing something fundamentally different without giving any detailed suguaring or semantics (or code). -Joe > // any block > { > int c; > > try FileReader reader = new FileReader( source ); > try FileWriter writer = new FileWriter( target ); > > while( (c = reader.read()) != -1 ) > writer.write(c); > } > > The [try ResourceSpecification] statement can appear anywhere in a > block. When the enclosing block completes, close() methods are > invoked. > > It's almost as if we have destructors > > public void copy(File source, File target) throws IOException > { > int c; > > try FileReader reader = new FileReader( source ); > try FileWriter writer = new FileWriter( target ); > > while( (c = reader.read()) != -1 ) > writer.write(c); > > } // reader and writer will be closed upon method completion > > Since we piggyback it on an existing block, we can avoid one > indentation, and making code more readable. Compatibility isn't > broken, the new behavior of the block only arise if the new type of > statement appears inside. > > The "try" keyword probably sounds unnatural for this purpose. Maybe we > can use some other keyword or symbol. > > IDE should warn when it appears that an auto-closeable resource is > not, but should be, initialized this way. > > Note, the auto-close behavior stays the same even if the enclosing > block is a try block > > try > { > int c; > > try FileReader reader = new FileReader( source ); > try FileWriter writer = new FileWriter( target ); > > while( (c = reader.read()) != -1 ) > writer.write(c); > } > catch(IOException e) > { > // reader and writer already closed! > } > > Zhong Yu > > > > On Tue, Aug 24, 2010 at 8:40 AM, Serge Boulay wrote: > >> The "using" block in c# only allows one resource unless the resources are of >> the same type. To use multiple resources they are nested or stacked >> >> using (StreamWriter w1 = File.CreateText("W1")) >> using (StreamWriter w2 = File.CreateText("W2")) >> { >> // code here >> } >> >> instead of >> >> using (StreamWriter w1 = File.CreateText("W1")) >> { >> using (StreamWriter w2 = File.CreateText("W2")) >> { >> // code here >> } >> } >> >> Depending on the number of resources, the "using" block nesting can quickly >> get out of hand. >> >> >> >> >> >> On 8/24/10, Stephen Colebourne wrote: >> >>> On 24 August 2010 12:14, David Holmes wrote: >>> >>>>> (I guess this forms a case against the try-with-multiple-resources >>>>> statement in general. The list of semicolon-delimited declarations >>>>> enclosed by parentheses looks weird, anyway ;-) >>>>> >>>> I tend to agree the syntax is awkward and far less readable than simply >>>> nesting the try-with statements. >>>> >>> Overall, I think the semicolon, multi-resource, aspect is more complex >>> than the benefits it gives. Clearer code results from nesting the >>> statements. >>> >>> Stephen >>> >>> >>> >> > > From reinier at zwitserloot.com Tue Aug 24 13:30:45 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 24 Aug 2010 22:30:45 +0200 Subject: trying out the prototype In-Reply-To: References: <4C73A982.3060400@oracle.com> Message-ID: The way you describe it is exactly how Lombok's @Cleanup works. From my (possibly biased?) experience, its a fantastic solution. The usual format one ends up writing is either: public void foo() throws RelevantException { Type x = open(); x.doOperation(); } or: public void foo() { try { Type x = open(); x.doOperation(); } catch (RelevantException e) { handleOperationFailure(); } } where closing earlier is important, just add a call to x.close(); --Reinier Zwitserloot On Tue, Aug 24, 2010 at 8:37 PM, Zhong Yu wrote: > How about this: > > // any block > { > int c; > > try FileReader reader = new FileReader( source ); > try FileWriter writer = new FileWriter( target ); > > while( (c = reader.read()) != -1 ) > writer.write(c); > } > > The [try ResourceSpecification] statement can appear anywhere in a > block. When the enclosing block completes, close() methods are > invoked. > > It's almost as if we have destructors > > public void copy(File source, File target) throws IOException > { > int c; > > try FileReader reader = new FileReader( source ); > try FileWriter writer = new FileWriter( target ); > > while( (c = reader.read()) != -1 ) > writer.write(c); > > } // reader and writer will be closed upon method completion > > Since we piggyback it on an existing block, we can avoid one > indentation, and making code more readable. Compatibility isn't > broken, the new behavior of the block only arise if the new type of > statement appears inside. > > The "try" keyword probably sounds unnatural for this purpose. Maybe we > can use some other keyword or symbol. > > IDE should warn when it appears that an auto-closeable resource is > not, but should be, initialized this way. > > Note, the auto-close behavior stays the same even if the enclosing > block is a try block > > try > { > int c; > > try FileReader reader = new FileReader( source ); > try FileWriter writer = new FileWriter( target ); > > while( (c = reader.read()) != -1 ) > writer.write(c); > } > catch(IOException e) > { > // reader and writer already closed! > } > > Zhong Yu > > > > On Tue, Aug 24, 2010 at 8:40 AM, Serge Boulay > wrote: > > The "using" block in c# only allows one resource unless the resources are > of > > the same type. To use multiple resources they are nested or stacked > > > > using (StreamWriter w1 = File.CreateText("W1")) > > using (StreamWriter w2 = File.CreateText("W2")) > > { > > // code here > > } > > > > instead of > > > > using (StreamWriter w1 = File.CreateText("W1")) > > { > > using (StreamWriter w2 = File.CreateText("W2")) > > { > > // code here > > } > > } > > > > Depending on the number of resources, the "using" block nesting can > quickly > > get out of hand. > > > > > > > > > > > > On 8/24/10, Stephen Colebourne wrote: > >> > >> On 24 August 2010 12:14, David Holmes wrote: > >> >> (I guess this forms a case against the try-with-multiple-resources > >> >> statement in general. The list of semicolon-delimited declarations > >> >> enclosed by parentheses looks weird, anyway ;-) > >> > > >> > I tend to agree the syntax is awkward and far less readable than > simply > >> > nesting the try-with statements. > >> > >> Overall, I think the semicolon, multi-resource, aspect is more complex > >> than the benefits it gives. Clearer code results from nesting the > >> statements. > >> > >> Stephen > >> > >> > > > > > > From howard.lovatt at gmail.com Tue Aug 24 21:41:39 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Wed, 25 Aug 2010 14:41:39 +1000 Subject: trying out the prototype Message-ID: Zhong Yu, This idea, auto closing when the variable goes out of scope, was discussed reasonably thoroughly much earlier in the Project Coin cycle. I thought it was the best solution however others, who have a vote unlike me, preferred the try block solution. -- Howard. Zhong Yu zhong.j.yu at gmail.com Tue Aug 24 11:37:23 PDT 2010 wrote: How about this: // any block { int c; try FileReader reader = new FileReader( source ); try FileWriter writer = new FileWriter( target ); while( (c = reader.read()) != -1 ) writer.write(c); } The [try ResourceSpecification] statement can appear anywhere in a block. When the enclosing block completes, close() methods are invoked. It's almost as if we have destructors public void copy(File source, File target) throws IOException { int c; try FileReader reader = new FileReader( source ); try FileWriter writer = new FileWriter( target ); while( (c = reader.read()) != -1 ) writer.write(c); } // reader and writer will be closed upon method completion Since we piggyback it on an existing block, we can avoid one indentation, and making code more readable. Compatibility isn't broken, the new behavior of the block only arise if the new type of statement appears inside. The "try" keyword probably sounds unnatural for this purpose. Maybe we can use some other keyword or symbol. IDE should warn when it appears that an auto-closeable resource is not, but should be, initialized this way. Note, the auto-close behavior stays the same even if the enclosing block is a try block try { int c; try FileReader reader = new FileReader( source ); try FileWriter writer = new FileWriter( target ); while( (c = reader.read()) != -1 ) writer.write(c); } catch(IOException e) { // reader and writer already closed! } Zhong Yu From mcnepp02 at googlemail.com Wed Aug 25 03:01:02 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Wed, 25 Aug 2010 10:01:02 +0000 Subject: trying out the prototype In-Reply-To: <4C741462.7060908@oracle.com> References: <4C741462.7060908@oracle.com> Message-ID: 2010/8/24 Joe Darcy : > > With N resources, there are possibly N+1 exceptions that can come out of the > try-with-resources statement, 1 from the block itself and 1 from each of the > close calls. ?Only one of those exceptions can be the one which gets > propagated out of the block. > > As covered in the other recent thread, the first exception thrown is > estimated to be the most informative one about what actually went wrong. > > -Joe > What I do understand is that the exception thrown from the block is considered more important than the exception thrown by the same resource afterwards, when it is being closed. I just doubt that you can make a similarily educated guess about the relative importance of exceptions thrown by unrelated resources. Here is a simple example: try(Writer out = new FileWriter("output.txt"; Reader in = new FileReader("input.txt")) { // Code to copy from in to out. } Now, if the constructor of 'in' throws a (relatively harmless) FileNotFoundException, the much more serious DiskFullException thrown by the close() method of 'out' will be lost. From David.Holmes at oracle.com Wed Aug 25 03:58:16 2010 From: David.Holmes at oracle.com (David Holmes) Date: Wed, 25 Aug 2010 20:58:16 +1000 Subject: suppressedException semantics In-Reply-To: References: <4C734EB0.7070103@oracle.com> <4C73A8BD.3090003@oracle.com> Message-ID: <4C74F748.7070109@oracle.com> Gernot Neppert said the following on 08/24/10 22:29: >> Well I disagree that the exception in the try block is necessarily more >> important than the one in the finally block. > > It might not be more important, but it might be the only one that you > can spot by looking at the code: I was referring to try-finally, not try-with. > try(Reader reader = new FileReader("contents.txt")) > { > char[] buf = new char[1000]; > int read; > while(0 < (read = reader.read(buf))) > { > // Do something > } > } > > Wouldn't you want the above block to re-throw exceptions from the > constructor or from 'read', rather than from an 'invisible' exception > source? This really is an argument against hiding the code in the first place. When you read the above you have to implicitly "see" the hidden close that might also throw an exception. Regardless of which exception is thrown you will want/need to follow the chain to get the full picture of what has gone wrong. David Holmes > (See also my other post suggesting that the compiler might be more > helpful in pointing at 'hidden' exception sources) From David.Holmes at oracle.com Wed Aug 25 04:03:04 2010 From: David.Holmes at oracle.com (David Holmes) Date: Wed, 25 Aug 2010 21:03:04 +1000 Subject: suppressedException semantics In-Reply-To: References: <4C734EB0.7070103@oracle.com> <4C73A8BD.3090003@oracle.com> Message-ID: <4C74F868.2040401@oracle.com> Reinier Zwitserloot said the following on 08/24/10 22:42: > Yes, it really matters. No current tools are capable of reporting > suppressed exceptions. I don't see how the lack of tools is relevant to the question. You will want to follow the chain of exceptions no matter which one is chosen to be thrown. > Between the causality chain and each exception in > it having suppressed exceptions, with all of THOSE potentially also > having a causality chain and further suppressed exceptions, a single > problem can result in many tens of stack traces. Making sure there is > such a thing as the primary trace amongst the set, and making sure that > the odds are good this one exception trace is more useful than the > others, is obviously (to me, anyway), a worthwhile endeavour, and is > certainly worth a little inconsistency. It is far from obvious to me that if there are "many tens of stack traces" then there even exists a "primary" one, let alone that that will be the exception being thrown under the current proposal. Once you have the possibility of suppressed exceptions then for any exception thrown you need to follow the chain. If you do that then you will see the full picture. In which case there is no need to have semantics that run counter to existing language exception semantics. YMMV. David Holmes > > --Reinier Zwitserloot > > > > On Tue, Aug 24, 2010 at 1:10 PM, David Holmes > wrote: > > Reinier Zwitserloot said the following on 08/24/10 20:20: > > I get the feeling Paul Benedict is saying the opposite of what David > Holmes is saying, which is a bit confusing. Paul: David is > suggesting > that the original exception should NOT be thrown in the new trywith > construct, to mirror the behaviour of what happens in existing > try/finally blocks. > > > I haven't seen Paul's mail as I just started subscribing. Sorry if I > seem to be changing the tack of an ongoing discussion. These are > just my views. > > > David: The idea behind throwing the original and tacking on any > further exceptions as suppressed ones is because the original one is > simply better. If for example a network connection fails due to for > example a broken pipe, the original exception will say so. If I then > close a bunch of resources related to the socket, all sorts of > further exceptions will fall out, mostly based around the notion > that > the entire socket has become invalidated. These may no longer state > the original reason for the failure of the socket (broken pipe). > Also, the point at which the socket broke, is when the original > exception occurred. Its stack trace is the best one, of all > traces of > all thrown exceptions, in that its closest to the actual state > of the > stack at the time the problem occurred. > > > But does it really matter as long as the less-better exception > reports the original better one? This would be just like the way the > "cause" works today - the final exception is not the key one, but > the one that caused it. I see the trywith proposal as running > counter to try-finally and to the current "caused-by" semantics. As > long as the exception you catch will print or otherwise make > available the chain of exceptions, then you have what you need. In > which case a simpler mechanism that is consistent with existing > language and API features is preferable in my view. > > > Of course, tweaking how standard try/finally works where the finally > block throws its own exception is not possible, because that would > break backwards compatibility. There is indeed a slight > inconsistency > in having trywith work differently from try/finally, but in > retrospect, if suppressedexceptions had been available from oak 1.0, > having the exception in the try block be 'more important' than > further exceptions is clearly the right way to go. Thus, where > we can > switch to the better option without breaking backwards > compatibility, > we do, and where we can't, we don't. Seems reasonable to me. > > > Well I disagree that the exception in the try block is necessarily more > important than the one in the finally block. The flaw in 1.0 was that > you lost the first exception. > > Cheers, > David > > > --Reinier Zwitserloot > > > > On Tue, Aug 24, 2010 at 6:46 AM, David Holmes > > >> wrote: > > I realize that I am late to the game here but reading Joe's latest > ARM proposal (and having looked into the issues with > pre-allocated exceptions) I find that the semantics of > suppressed exceptions for try-with-resources are actually the > opposite to what I initially thought. > > Taking regular Java as it stands, given: > > try { throw new A(); } finally { throw new B(); } > > the try-finally will always complete by throwing B and the fact that > A occurred has been lost. Exception B has suppressed exception A in > this case. So I thought that the addition of > suppressedExceptions was > a way for B to indicate that it has suppressed A. This could be > considered a general language extension independent of > try-with-resources: it is simply a way for exceptions that would be > lost to be "chained" to the exception that replaced them. (And in > such an extension I probably would not make addSuppressedException a > generally available API.) > > What try-with-resources proposes is actually suppressing B (when > it comes from an AutoCloseable) and propagating A. I find this > somewhat confusing, especially when the argument of whether to > suppress only Exception but not Error etc is taken into account. > It is not apparent > to me why the exception from the try block is more important > than the > exception from the finally block? As long as A can be found from B > does it matter which is actually thrown? I would suggest that > the try-with-resources code transformation would be a lot > simpler if it > did not change the exception that would naturally be thrown from the > finally clause. It would also make it a moot point whether to > distinguish Error from Exception etc. > > I just can't help but think that this is more complex than it needs > to be. And at the same time that the "suppressed exception" > mechanism > is not as generally useful as it could be. > > And yes I've just donned my flak-jacket ;-) > > Cheers, David Holmes > > > From David.Holmes at oracle.com Wed Aug 25 04:20:51 2010 From: David.Holmes at oracle.com (David Holmes) Date: Wed, 25 Aug 2010 21:20:51 +1000 Subject: suppressedException semantics In-Reply-To: <4C741250.9010702@oracle.com> References: <4C734EB0.7070103@oracle.com> <4C741250.9010702@oracle.com> Message-ID: <4C74FC93.8000303@oracle.com> Hi Joe, Joe Darcy said the following on 08/25/10 04:41: > David Holmes wrote: >> I realize that I am late to the game here but reading Joe's latest ARM >> proposal (and having looked into the issues with pre-allocated >> exceptions) I find that the semantics of suppressed exceptions for >> try-with-resources are actually the opposite to what I initially thought. >> >> Taking regular Java as it stands, given: >> >> try { >> throw new A(); >> } >> finally { >> throw new B(); >> } >> >> the try-finally will always complete by throwing B and the fact that A >> occurred has been lost. Exception B has suppressed exception A in this >> case. > > Just to be clear on the proposal, in the code example two exceptions are > thrown and only one, B, propagates out. All information about the > existence of A is lost. Yes. > The proposal could, but does *not*, change the semantics of try-finally > *without* a resource so that A was listed as a suppressed exception of B. Yes again. While not currently proposed it would seem to me that suppressedExceptions should be applied to the existing try-finally case to fix that long standing hole/wart/imperfection in the language. >> I find this somewhat confusing, especially when the argument of >> whether to suppress only Exception but not Error etc is taken into >> account. It is not apparent to me why the exception from the try block >> is more important than the exception from the finally block? > > In my estimation, the first exception thrown is the one most likely to > be information of what exactly went wrong as opposed to just being a > cascading consequence of prior exceptions/problems. I can buy that in the simple one-resource case, particularly for the classic I/O examples. But it isn't an absolute truth and once multiple resources and layers of exceptions are involved then I don't think there can reasonably be a general notion of which is "more important" or "more informative". In general this can only be answered in context - as per your comments below. So while I can see some merit in the simple common use-case acting the opposite of existing try-finally semantics, I don't think this "scales" so to me the inconsistency and added complexity is not worth the benefit supplied to that simple use-case. As always YMMV. Cheers, David Holmes >> As long as A can be found from B does it matter which is actually >> thrown? I would suggest that the try-with-resources code >> transformation would be a lot simpler if it did not change the >> exception that would naturally be thrown from the finally clause. It >> would also make it a moot point whether to distinguish Error from >> Exception etc. >> >> I just can't help but think that this is more complex than it needs to >> be. And at the same time that the "suppressed exception" mechanism is >> not as generally useful as it could be. >> >> And yes I've just donned my flak-jacket ;-) >> >> Cheers, >> David Holmes >> >> > > First-thrown-exception wins and last-thrown-exception wins are two > simple and predictable polices toward handling suppression. I find "I'm > a worse problem then you" logic at each point along the way unappealing > since it would be hard to know what throwable would eventually come > out. Of two errors, which is worse? Is a checked exception worse than > a runtime exception? Is a non-error, non-java.lang.Exception Throwable > worse than an Error? ... > > -Joe From R.Spilker at topdesk.com Wed Aug 25 05:33:09 2010 From: R.Spilker at topdesk.com (=?windows-1252?Q?Roel_Spilker?=) Date: Wed, 25 Aug 2010 14:33:09 +0200 Subject: suppressedException semantics In-Reply-To: <4C74F868.2040401@oracle.com> References: Message-ID: > Once you have the possibility of suppressed exceptions then > for any exception thrown you need to follow the chain. If you > do that then you will see the full picture. In which case > there is no need to have semantics that run counter to > existing language exception semantics. > Actually, with the suppressed exceptions, you need to "follow the tree". Each exception now potentially has a cause and a list of suppressed exceptions, recursively. Roel From reinier at zwitserloot.com Wed Aug 25 06:49:57 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 25 Aug 2010 15:49:57 +0200 Subject: suppressedException semantics In-Reply-To: <4C74F868.2040401@oracle.com> References: <4C734EB0.7070103@oracle.com> <4C73A8BD.3090003@oracle.com> <4C74F868.2040401@oracle.com> Message-ID: On Wed, Aug 25, 2010 at 1:03 PM, David Holmes wrote: > > I don't see how the lack of tools is relevant to the question. You will > want to follow the chain of exceptions no matter which one is chosen to be > thrown. > > Why? Once I see a trace that explains the problem, I stop reading. The faster that happens, the happier I'd be. > It is far from obvious to me that if there are "many tens of stack traces" > then there even exists a "primary" one, let alone that that will be the > exception being thrown under the current proposal. > > One of them is going to be printed first. Unless you're suggesting we officially state that the order in which exceptions print will henceforth be undetermined, but I don't think that's a good idea. From zhong.j.yu at gmail.com Wed Aug 25 09:54:32 2010 From: zhong.j.yu at gmail.com (Zhong Yu) Date: Wed, 25 Aug 2010 11:54:32 -0500 Subject: suppressedException semantics In-Reply-To: <4C74F748.7070109@oracle.com> References: <4C734EB0.7070103@oracle.com> <4C73A8BD.3090003@oracle.com> <4C74F748.7070109@oracle.com> Message-ID: On Wed, Aug 25, 2010 at 5:58 AM, David Holmes wrote: > Gernot Neppert said the following on 08/24/10 22:29: >>> Well I disagree that the exception in the try block is necessarily more >>> important than the one in the finally block. >> >> It might not be more important, but it might be the only one that you >> can spot by looking at the code: > > I was referring to try-finally, not try-with. > >> try(Reader reader = new FileReader("contents.txt")) >> { >> ? ?char[] buf = new char[1000]; >> ? ?int read; >> ? ?while(0 < (read = reader.read(buf))) >> ? { >> ? ?// Do something >> ? } >> } >> >> Wouldn't you want the above block to re-throw exceptions from the >> constructor or from 'read', rather than from an 'invisible' exception >> source? > > This really is an argument against hiding the code in the first place. > When you read the above you have to implicitly "see" the hidden close > that might also throw an exception. Was there any proposal to explicitly close(), with a cleaner syntax than the traditional try-finally? > > Regardless of which exception is thrown you will want/need to follow the > chain to get the full picture of what has gone wrong. > > David Holmes > >> (See also my other post suggesting that the compiler might be more >> helpful in pointing at 'hidden' exception sources) > > From joe.darcy at oracle.com Wed Aug 25 10:08:17 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Wed, 25 Aug 2010 10:08:17 -0700 Subject: trying out the prototype In-Reply-To: References: <4C741462.7060908@oracle.com> Message-ID: <4C754E01.1060306@oracle.com> Gernot Neppert wrote: > 2010/8/24 Joe Darcy : > >> With N resources, there are possibly N+1 exceptions that can come out of the >> try-with-resources statement, 1 from the block itself and 1 from each of the >> close calls. Only one of those exceptions can be the one which gets >> propagated out of the block. >> >> As covered in the other recent thread, the first exception thrown is >> estimated to be the most informative one about what actually went wrong. >> >> -Joe >> >> > > > What I do understand is that the exception thrown from the block is > considered more important than the exception thrown by the same > resource afterwards, when it is being closed. > > I just doubt that you can make a similarily educated guess about the > relative importance of exceptions thrown by unrelated resources. > Here is a simple example: > > try(Writer out = new FileWriter("output.txt"; Reader in = new > FileReader("input.txt")) > { > // Code to copy from in to out. > } > > Now, if the constructor of 'in' throws a (relatively harmless) > FileNotFoundException, the much more serious DiskFullException thrown > by the close() method of 'out' will be lost. > It is trivial to generate situations where any fixed policy of suppressing exceptions gives the "wrong" answer about propagating the most informative exception. The coin-dev list has hosted longs threads speculating how try-with-resources would and would not work in practice. We don't have to limit ourselves to speculating anymore: since there is a prototype which can be easily downloaded and run on many platforms, people can *use the feature* and report back how it works (or not) *in practice*. -Joe From neal at gafter.com Wed Aug 25 10:51:04 2010 From: neal at gafter.com (Neal Gafter) Date: Wed, 25 Aug 2010 10:51:04 -0700 Subject: trying out the prototype In-Reply-To: <4C754E01.1060306@oracle.com> References: <4C741462.7060908@oracle.com> <4C754E01.1060306@oracle.com> Message-ID: On Wed, Aug 25, 2010 at 10:08 AM, Joe Darcy wrote: > We don't have to limit ourselves to speculating anymore: since there is > a prototype which can be easily downloaded and run on many platforms, > people can *use the feature* and report back how it works (or not) *in > practice*. > Unfortunately, using the prototype puts us at risk of infringing Oracle's patent portfolio, as openjdk7 and its variants are not licensed Java SE implementations. From jjb at google.com Wed Aug 25 11:06:39 2010 From: jjb at google.com (Joshua Bloch) Date: Wed, 25 Aug 2010 11:06:39 -0700 Subject: trying out the prototype In-Reply-To: <4C73A982.3060400@oracle.com> References: <4C73A982.3060400@oracle.com> Message-ID: David, I very much disagree with this one. I see it as a major win that you don't end up with multiple levels of indentation. Josh On Tue, Aug 24, 2010 at 4:14 AM, David Holmes wrote: > Gernot Neppert said the following on 08/24/10 19:27: > > 2. If you use multiple Resources, an exception thrown by one of them > > will suppress exceptions thrown by the 'close()' invocation of others. > > While I can see some sense in suppressing exceptions from 'close()' of > > the same instance, I cannot see why this reasoning should apply to > > other instances. > > (I guess this forms a case against the try-with-multiple-resources > > statement in general. The list of semicolon-delimited declarations > > enclosed by parentheses looks weird, anyway ;-) > > I tend to agree the syntax is awkward and far less readable than simply > nesting the try-with statements. > > David Holmes > > > Here's an example: > > > > class ThrowsOnRead extends Reader > > { > > public int read(char[] cbuf, int off, int len) throws IOException > > { > > throw new IOException(); > > } > > > > @Override > > public void close() throws IOException > > { > > > > } > > } > > > > class ThrowsOnClose extends Reader > > { > > public void close() throws IOException > > { > > throw new IOException(); > > } > > > > public int read(char[] cbuf, int off, int len) throws IOException > > { > > return 0; > > } > > } > > > > > > > > public class TestAutoClose { > > > > public static void main(String[] args) throws IOException { > > try(Reader rdr1 = new ThrowsOnRead(); Reader rdr2 = new > ThrowsOnClose()) > > { > > rdr1.read(); // Why is this exception more important > than the > > one thrown by rdr2.close() ? > > } > > } > > } > > > > From jjb at google.com Wed Aug 25 11:08:59 2010 From: jjb at google.com (Joshua Bloch) Date: Wed, 25 Aug 2010 11:08:59 -0700 Subject: trying out the prototype In-Reply-To: References: <4C73A982.3060400@oracle.com> Message-ID: Yep.I have heard this from C# users for seven years or so. I was told by them that we should not repeat this error. Josh On Tue, Aug 24, 2010 at 6:40 AM, Serge Boulay wrote: > The "using" block in c# only allows one resource unless the resources are > of > the same type. To use multiple resources they are nested or stacked > > using (StreamWriter w1 = File.CreateText("W1")) > using (StreamWriter w2 = File.CreateText("W2")) > { > // code here > } > > instead of > > using (StreamWriter w1 = File.CreateText("W1")) > { > using (StreamWriter w2 = File.CreateText("W2")) > { > // code here > } > } > > Depending on the number of resources, the "using" block nesting can quickly > get out of hand. > > > > > > On 8/24/10, Stephen Colebourne wrote: > > > > On 24 August 2010 12:14, David Holmes wrote: > > >> (I guess this forms a case against the try-with-multiple-resources > > >> statement in general. The list of semicolon-delimited declarations > > >> enclosed by parentheses looks weird, anyway ;-) > > > > > > I tend to agree the syntax is awkward and far less readable than simply > > > nesting the try-with statements. > > > > Overall, I think the semicolon, multi-resource, aspect is more complex > > than the benefits it gives. Clearer code results from nesting the > > statements. > > > > Stephen > > > > > > From David.Holmes at oracle.com Wed Aug 25 15:28:22 2010 From: David.Holmes at oracle.com (David Holmes) Date: Thu, 26 Aug 2010 08:28:22 +1000 Subject: suppressedException semantics In-Reply-To: References: <4C734EB0.7070103@oracle.com> <4C73A8BD.3090003@oracle.com> <4C74F868.2040401@oracle.com> Message-ID: <4C759906.6050902@oracle.com> Reinier Zwitserloot said the following on 08/25/10 23:49: > On Wed, Aug 25, 2010 at 1:03 PM, David Holmes > wrote: > > > I don't see how the lack of tools is relevant to the question. You > will want to follow the chain of exceptions no matter which one is > chosen to be thrown. > > Why? Once I see a trace that explains the problem, I stop reading. The > faster that happens, the happier I'd be. Well if you're sure none of the other exceptions indicate real problems that need to be addressed, that is your call. > It is far from obvious to me that if there are "many tens of stack > traces" then there even exists a "primary" one, let alone that that > will be the exception being thrown under the current proposal. > > > One of them is going to be printed first. Unless you're suggesting we > officially state that the order in which exceptions print will > henceforth be undetermined, but I don't think that's a good idea. Of course one of them will be printed first - and then we have issues of printing breadth first or depth first with the cause and suppressedExceptions. My point is that it doesn't matter which one is printed first, so why not stick with an order that is consistent with the existing language semantics? I don't see cost:benefit in the right proportions here in the general case. If we were limited to one resource per try-with those proportions improve significantly. As I've said YMMV. David From jjb at google.com Wed Aug 25 17:58:47 2010 From: jjb at google.com (Joshua Bloch) Date: Wed, 25 Aug 2010 17:58:47 -0700 Subject: suppressedException semantics In-Reply-To: <4C734EB0.7070103@oracle.com> References: <4C734EB0.7070103@oracle.com> Message-ID: FWIW, I do wish that Java's entire exception handling mechanism worked more like ARM's. I was aware of this when I designed it. But it's too late to change the semantics of what happens when an arbitrary exception is thrown when another one is already "on the stack." I think we did the best we could under the circumstances. Josh On Mon, Aug 23, 2010 at 9:46 PM, David Holmes wrote: > I realize that I am late to the game here but reading Joe's latest ARM > proposal (and having looked into the issues with pre-allocated > exceptions) I find that the semantics of suppressed exceptions for > try-with-resources are actually the opposite to what I initially thought. > > Taking regular Java as it stands, given: > > try { > throw new A(); > } > finally { > throw new B(); > } > > the try-finally will always complete by throwing B and the fact that A > occurred has been lost. Exception B has suppressed exception A in this > case. So I thought that the addition of suppressedExceptions was a way > for B to indicate that it has suppressed A. This could be considered a > general language extension independent of try-with-resources: it is > simply a way for exceptions that would be lost to be "chained" to the > exception that replaced them. (And in such an extension I probably would > not make addSuppressedException a generally available API.) > > What try-with-resources proposes is actually suppressing B (when it > comes from an AutoCloseable) and propagating A. I find this somewhat > confusing, especially when the argument of whether to suppress only > Exception but not Error etc is taken into account. It is not apparent to > me why the exception from the try block is more important than the > exception from the finally block? As long as A can be found from B does > it matter which is actually thrown? I would suggest that the > try-with-resources code transformation would be a lot simpler if it did > not change the exception that would naturally be thrown from the finally > clause. It would also make it a moot point whether to distinguish Error > from Exception etc. > > I just can't help but think that this is more complex than it needs to > be. And at the same time that the "suppressed exception" mechanism is > not as generally useful as it could be. > > And yes I've just donned my flak-jacket ;-) > > Cheers, > David Holmes > > From neal at gafter.com Thu Aug 26 17:10:02 2010 From: neal at gafter.com (Neal Gafter) Date: Thu, 26 Aug 2010 17:10:02 -0700 Subject: suppressedException semantics In-Reply-To: References: <4C734EB0.7070103@oracle.com> Message-ID: Brian Goetz wrote this on lambda-dev: On Fri, Jul 16, 2010 at 10:07 AM, Brian Goetz wrote: > And, given that inner classes [try blocks] *already* suffer from the > accidental [exception] shadowing > problem, creating a mechanism that goes the other way (even if the other > way > is absolutely right!) is even more confusing for Java developers, who now > have > to keep track of two separate and inconsistent bits of puzzlerhood. > (Editorial text added in brackets) This argument appears to apply precisely as well to exception shadowing as it does to name shadowing. On Wed, Aug 25, 2010 at 5:58 PM, Joshua Bloch wrote: > FWIW, I do wish that Java's entire exception handling mechanism worked more > like ARM's. I was aware of this when I designed it. But it's too late to > change the semantics of what happens when an arbitrary exception is thrown > when another one is already "on the stack." I think we did the best we > could under the circumstances. > > Josh > > On Mon, Aug 23, 2010 at 9:46 PM, David Holmes >wrote: > > > I realize that I am late to the game here but reading Joe's latest ARM > > proposal (and having looked into the issues with pre-allocated > > exceptions) I find that the semantics of suppressed exceptions for > > try-with-resources are actually the opposite to what I initially thought. > > > > Taking regular Java as it stands, given: > > > > try { > > throw new A(); > > } > > finally { > > throw new B(); > > } > > > > the try-finally will always complete by throwing B and the fact that A > > occurred has been lost. Exception B has suppressed exception A in this > > case. So I thought that the addition of suppressedExceptions was a way > > for B to indicate that it has suppressed A. This could be considered a > > general language extension independent of try-with-resources: it is > > simply a way for exceptions that would be lost to be "chained" to the > > exception that replaced them. (And in such an extension I probably would > > not make addSuppressedException a generally available API.) > > > > What try-with-resources proposes is actually suppressing B (when it > > comes from an AutoCloseable) and propagating A. I find this somewhat > > confusing, especially when the argument of whether to suppress only > > Exception but not Error etc is taken into account. It is not apparent to > > me why the exception from the try block is more important than the > > exception from the finally block? As long as A can be found from B does > > it matter which is actually thrown? I would suggest that the > > try-with-resources code transformation would be a lot simpler if it did > > not change the exception that would naturally be thrown from the finally > > clause. It would also make it a moot point whether to distinguish Error > > from Exception etc. > > > > I just can't help but think that this is more complex than it needs to > > be. And at the same time that the "suppressed exception" mechanism is > > not as generally useful as it could be. > > > > And yes I've just donned my flak-jacket ;-) > > > > Cheers, > > David Holmes > > > > > > From zhong.j.yu at gmail.com Thu Aug 26 23:27:59 2010 From: zhong.j.yu at gmail.com (Zhong Yu) Date: Fri, 27 Aug 2010 01:27:59 -0500 Subject: suppressedException semantics In-Reply-To: References: <4C734EB0.7070103@oracle.com> Message-ID: I guess that majority of programmers only care about how the stack trace is printed, and most of us would love to see the "primary exception" printed first. After all, it is the first exception that occurred, and should be the first one to be investigated. Therefore as long as the "primary exception" is printed first, we are satisfied. Programmatically: let say e_a of type EA is an exception thrown in the try block, and e_b of type EB is an exception thrown by close(). If the exception catcher wants to handle different cases differently, e_a and e_b must be distinguishable. Either they are of different types, or they have distinguishable field values ("message" doesn't count!). Seriously, which JDK class does that? File? Socket? SQL? Usually, we are forced to catch one exception of one type, not knowing what exactly it is. There is nothing we can do with it but print its stack trace. Let's say e_a and e_b are distinguishable. The meticulous programmer tries to handle 3 possible cases differently. He's aware that both e_a and e_b could have occurred in serial, he needs a way to pattern match this case, and extract both exceptions. Since there is no such thing as catch(EA e_a, EB e_b), our hero has to check the spec, and grudgingly does what's necessary. Which exception suppressed which, it doesn't matter, both choices produce ugly code. Facing all kinds of possible combinations of e_a_1, e_a_2... e_a_m, e_b_1 ... e_b_n, instead of catching each individually and further checking the suppressed list of each, the following generic catch code makes things easier catch(Ex e_x) // Ex is a common super type of EA_1 ... EA_m, EB_1 ... EB_n { Ex[] exceptions = flat(e_x); // e_x and suppressed(if any), ordered *chronically* for(Ex e : exceptions) if(e instanceof EA_1) ... } Here, the code doesn't visually depend on whether e_a or e_b was thrown. Either way works. If nobody cares programatically, the argument for spec consistency wins. I'm in the camp of David. (or more sinisterly - we could change the semantics of try-finally and switch which exception is suppressed, to line up with Joshua's ARM; no real world program will be broken...) Zhong Yu On Thu, Aug 26, 2010 at 7:10 PM, Neal Gafter wrote: > Brian Goetz wrote this on lambda-dev: >