From brian.goetz at oracle.com Tue Nov 1 19:58:38 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 1 Nov 2022 15:58:38 -0400 Subject: Draft Spec for Fourth Preview of Pattern Matching for Switch (JEP 433) and Second Preview of Record Patterns (JEP 432) now available In-Reply-To: <586AADA9-E4B6-4656-A68E-5436BC188A2B@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <586AADA9-E4B6-4656-A68E-5436BC188A2B@oracle.com> Message-ID: <8c543edd-fa16-1776-3aea-dde13d6c9687@oracle.com> > --- > > 5.5: There's this "downcast compatible" notion that was apparently introduced with instanceof pattern matching. It means a cast is legal and not unchecked. Ok. But?not all legal casts are downcasts, right? It's pretty confusing to use a term that suggests that they are. I tripped over this a few times as well, until I just memorized what "DC" meant.? A better name is welcome. > 6.3.3.1: Maybe someday we'll have expressions nested in patterns, but for now isn't it meaningless to ask whether a pattern variable is in scope within another part of the same pattern? This may be leftover from when we had guarded patterns `P && e`, where `e` was part of the pattern? > - It's weird that 'null' is the one case constant that can't come after a 'default', given that 'null' is the one value that can't be handled by a 'default'. :-) Since we have to allow other case constants after 'default' anyway, I think it's best to allow 'null' as one more. ("default dominates everything except constants" is a rule I can remember.) I suspect that this can be simplified further, and will have to be anyway when we do underscore (since we will be allowing multiple patterns on a single case.) > 14.11.1: I don't think we prevent this scenario: > > switch (obj) { case String s: case Object o: } > > The rules about duplicate pattern labels apply to "a statement is labeled...". There's no labeled statement here. > > I think we should probably prohibit this, for the same code hygiene reason that we prohibit it before a statement group that doesn't try to use any of the variables. > > (This would not be a legal switch expression, because switch expressions can't fall out. But enhanced switch statements can, as long as they're exhaustive.) Let's be clear about why we'd be prohibiting this.? Arguably, this could be OK as long as there is no use of either `s` or `o` here. But that seems pretty useless. The basis for disallowing should be that you can't fall into, or out of, a case label that declares a pattern variable. > 14.11.2: Design suggestion: rename "enhanced switch" to "pattern switch", define it as only those switches that make use of patterns, and don't worry about the remaining "switch with new features" corner cases. It's just such an important concept that I think there's a benefit to making the distinction really clean and obvious. E.g., asking someone new to Java to memorize the ad hoc set of types that don't demand exhaustiveness seems unhelpfully complicated. > > (Corner cases I'm thinking about: want to use a null constant but not be exhaustive? Fine. Want to have an Object input type but an empty switch body? Pointless, but fine. Etc.) I think the motivation here is that we want to minimize the surface area of non-exhaustive switches, by quarantining the "need not be exhaustive" to those that would have compiled under Java 8. "Switches must be exhaustive, except for statement switches over T1..Tn with all constant labels." > 14.11.3, 15.28.2: Opinionated take: we're continuing to throw ICCE when an unmatched enum constant slips through a switch, because it would be a (behaviorally) incompatible change to throw something else. Meanwhile, unmatched sealed classes get a MatchException. I think there are a tiny number of people who would notice if we changed from ICCE to MatchException for enums too, and a lot more people who will have to cope with the historical baggage going forward if we don't. We should just standardize on MatchException. Probably better, it's a small incompatibility.? No one could be relying on the ICCE... > 14.14.2: I'm sure there's been some discussion about this already, but the use of MatchException for nulls in 'for' loops but NPE for nulls in switches also seems like a sad historical wart. What's wrong with an NPE from a 'for' loop? I think if the RHS of the foreach loop is null, we should NPE (as before.)? But if one of the _elements_ of the RHS array/iterable is null, then we should ME on the record pattern.? (Otherwise we have a sharp edge between a top-level record pattern and a nested record pattern.) > 14.30.1: Parenthesized patterns are no fun for a spec writer. :-) Are they actually useful? I'm not sure I've seen an example demonstrating what they're for. (The JEP only talks about them abstractly.) They were added when we were doing guarded patterns and never took them out.? They will be useful again when we have & and | for patterns; right now they're just taking up space. > 14.30.1, 14.30.2: I'm not sold on *any patterns*, *resolved patterns*, and *executable switch blocks*. > > The semantics are fine?some type patterns will match null, others will not. But it seems to me that this can be a property of the type pattern, one of many properties of programs that we determine at compile time. No need to frame it as rewriting a program into something else. (Compare the handling of the '+' operator. We don't rewrite to a non-denotable "concatenation expression".) > > Concretely: > - The pattern matching runtime rules can just say "the null reference matches a type pattern if the type pattern is unconditional". > - We can make it a little more clear that a type pattern is determined to be unconditional, or not, based on its context-dependent match type (is that what we call it?) > > For a *compiler*, it will be useful to come up with an encoding that preserves the compile-time "unconditional" property in bytecode. But that's a compiler problem, not something JLS needs to comment on. It is a property of the pattern *and the type being matched*.? We tried writing it the other way and it was not necessarily better.... > 14.30.3: A record pattern can't match null, but for the purpose of dominance, it's not clear to me why a record pattern can't be considered unconditional, and thus dominate the equivalent type pattern or a 'default'. Unconditional means "no runtime checks"; it's like a static cast for which we don't emit a checkcast.? Exhaustive means "satisfies the type system, but might have bad values" (null, novel enum constants, novel subtypes, at any level in the tree.) From daniel.smith at oracle.com Thu Nov 3 16:02:57 2022 From: daniel.smith at oracle.com (Dan Smith) Date: Thu, 3 Nov 2022 16:02:57 +0000 Subject: Draft Spec for Fourth Preview of Pattern Matching for Switch (JEP 433) and Second Preview of Record Patterns (JEP 432) now available In-Reply-To: <8c543edd-fa16-1776-3aea-dde13d6c9687@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <586AADA9-E4B6-4656-A68E-5436BC188A2B@oracle.com> <8c543edd-fa16-1776-3aea-dde13d6c9687@oracle.com> Message-ID: > On Nov 1, 2022, at 12:58 PM, Brian Goetz wrote: > >> 14.11.2: Design suggestion: rename "enhanced switch" to "pattern switch", define it as only those switches that make use of patterns, and don't worry about the remaining "switch with new features" corner cases. It's just such an important concept that I think there's a benefit to making the distinction really clean and obvious. E.g., asking someone new to Java to memorize the ad hoc set of types that don't demand exhaustiveness seems unhelpfully complicated. >> >> (Corner cases I'm thinking about: want to use a null constant but not be exhaustive? Fine. Want to have an Object input type but an empty switch body? Pointless, but fine. Etc.) > > I think the motivation here is that we want to minimize the surface area of non-exhaustive switches, by quarantining the "need not be exhaustive" to those that would have compiled under Java 8. "Switches must be exhaustive, except for statement switches over T1..Tn with all constant labels." Minimal surface area is good, but that can be at odds with minimal "perimeter"?that is, how hard is it to draw the line distinguishing the old style from the new style? I like making it about patterns because they're such an obvious departure from what came before, and what that gains in reduced perimeter seems to justify a small sacrifice of surface area. >> 14.14.2: I'm sure there's been some discussion about this already, but the use of MatchException for nulls in 'for' loops but NPE for nulls in switches also seems like a sad historical wart. What's wrong with an NPE from a 'for' loop? > > I think if the RHS of the foreach loop is null, we should NPE (as before.) But if one of the _elements_ of the RHS array/iterable is null, then we should ME on the record pattern. (Otherwise we have a sharp edge between a top-level record pattern and a nested record pattern.) Eventually, I guess the rewrite will be expressed as a 'let' expression (using whatever syntax we settle on): let Record(var x, var y) = iterator.next(); The right thing to do in for-each is thus whatever the right thing is to do in a 'let' statement. I'm kind of torn, because it seems straightforward to say this is an NPE (deconstructing a record is not that different from doing a field access). But it's true that a nested record pattern in a switch will cause a MatchException when given a null component value. Meanwhile, a top-level record pattern in a switch will cause an NPE. Hmm. No good way to make all of that consistent... >> 14.30.1, 14.30.2: I'm not sold on *any patterns*, *resolved patterns*, and *executable switch blocks*. >> >> The semantics are fine?some type patterns will match null, others will not. But it seems to me that this can be a property of the type pattern, one of many properties of programs that we determine at compile time. No need to frame it as rewriting a program into something else. (Compare the handling of the '+' operator. We don't rewrite to a non-denotable "concatenation expression".) >> >> Concretely: >> - The pattern matching runtime rules can just say "the null reference matches a type pattern if the type pattern is unconditional". >> - We can make it a little more clear that a type pattern is determined to be unconditional, or not, based on its context-dependent match type (is that what we call it?) >> >> For a *compiler*, it will be useful to come up with an encoding that preserves the compile-time "unconditional" property in bytecode. But that's a compiler problem, not something JLS needs to comment on. > > It is a property of the pattern *and the type being matched*. We tried writing it the other way and it was not necessarily better.... Yes, it's a property of the pattern derived from enclosing context?but this is nothing new. Like, the interpretation of names is heavily dependent on enclosing context. In any case, it's just a spec presentation question, so I suppose I can discuss further with Gavin and Alex and see what conclusion we come to. >> 14.30.3: A record pattern can't match null, but for the purpose of dominance, it's not clear to me why a record pattern can't be considered unconditional, and thus dominate the equivalent type pattern or a 'default'. > > Unconditional means "no runtime checks"; it's like a static cast for which we don't emit a checkcast. Exhaustive means "satisfies the type system, but might have bad values" (null, novel enum constants, novel subtypes, at any level in the tree.) "Unconditional" may be the wrong word, then, but my real complaint here is that I think a record pattern should be able to dominate an unconditional type pattern or a 'default' label. From forax at univ-mlv.fr Sat Nov 12 07:58:57 2022 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 12 Nov 2022 08:58:57 +0100 (CET) Subject: Retiring Checked Exceptions Was: Throwing Functions In-Reply-To: References: Message-ID: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> [promoted to amber-spec-experts] I think we should tackle this problem at its core and retire the notion of checked exceptions The written are on the wall since quite some time, but we have not yet acknowledge it. Let's recap the issue and the clues pointing in that direction. I believe the first straw can be tracked back to the inability of the type system to create a type variable containing the union of exceptions when generics where introduced in Java 5. It's the reason why there is no ThrowableConsumer, as an example, imagine that a stream can declare a checked exception Stream and a user call map() that takes a ThrowableFunction, we need a way to express that the resulting stream is that combine the exceptions of the original stream and the exceptions that may be raised by calling the function of map. Stream --> map(ThrowableFunction) --> Stream Or perhaps from the beginning of Java, adding a checked exception to a "throws" colors the function the same way the keyword async or Rust lifetime type information color a function [1]. Adding a checked exception to a function is not a backward compatible change. So we have some of idioms that beginners need to internalize to try workaround checked exceptions, - The oldest is i think, Thread.currentThread().interrupt() which allows to silence an InterruptedException at the price of continuing to execute the code until the next blocking call - UncheckedIOException and IOError that both wrap an IOException into an unchecked exception allowing tunneling of checked exceptions ; wrapping an IOException and unbundle it later. - Unsafe.rethrow (this one was retired) - the unfamous rethrow using erasure to see a checked exception as an unchecked exception static AssertionError rethrow(Throwable cause) throws T { throw (T) cause; } - IntelliJ has changed the default try/catch snippet to instead of calling printStackTrace() to throw a RuntimeException wrapping the exception. This simple change is i believe the best change to Java in the recent years (perhaps toes to toes with records), at least now the code of my students does not print the stack trace and resume its course when an exception occurs. try { ... } catch(FooException e) { throw new RuntimeException(e); } Also no language presented as potential successor of Java, neither Scala nor Kotlin have checked exceptions, because functions with checked exceptions do not compose. If Java wants to be the next Java, we will have to drop checked exceptions at some point. The good news is that seeing all exceptions as unchecked exceptions is a backward compatible change, "throws" can still be supported for documentation purpose, the compiler can emit a warning instead of an error if there is no catch corresponding to a checked exception and allow everyone to catch any exceptions in the code. I think we should recognize that the idea of checked exceptions was a good idea on paper but not a good one in practice and work to retire the concept of checked exceptions from Java. R?mi [1] https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ > From: "Nathan Reynolds" > To: "amber-dev" > Sent: Saturday, November 12, 2022 5:47:10 AM > Subject: Throwing Functions > I am sorry if I am very late to the discussion. Consumer, Function, Predicate, > and Supplier don't allow for throwing checked exceptions. This feature is > needed in many cases. What about adding a variant that allows for throwing > checked exceptions? For example, a ThrowableConsumer could be defined as > such... > public interface ThrowableConsumer > { > void accept(T t) throws E; > } > A method that receives this as a parameter could be defined as such... > public void process(ThrowableConsumer consume) > throws E > { > ... > } > The compiler takes care of ensuring the checked exception is dealt with in the > caller to process(). -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Sat Nov 12 15:44:32 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 12 Nov 2022 10:44:32 -0500 Subject: Retiring Checked Exceptions Was: Throwing Functions In-Reply-To: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> References: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> Message-ID: <86271a04-6d41-02aa-a13c-0426401c4e91@oracle.com> Counter-proposal: let's just retire the endless stream of "let's just get rid of checked exceptions" proposals instead. This is all well-traveled ground, and has all been brought up before (including by you several times.)? I get how attractive it is to "just" declare checked exceptions a mistake.? But even if it was, we know that trying to "fix" the "mistakes" of the past often only makes things worse. There is interesting research going on in the Scala community and elsewhere about better treatment of effects; some of this may bear fruit that might be a better approach than the "just uncheck them all."? In any case, I'm not interested in reopening this discussion at this time; we have plenty else on the priority list. Verdict: Motion Denied.? Leave is granted to refile your motion in 2025. On 11/12/2022 2:58 AM, Remi Forax wrote: > [promoted to amber-spec-experts] > > I think we should tackle this problem at its core and retire the > notion of checked exceptions > > The written are on the wall since quite some time, but we have not yet > acknowledge it. > > Let's recap the issue and the clues pointing in that direction. > > I believe the first straw can be tracked back to the inability of the > type system to create a type variable containing the union of > exceptions when generics where introduced in Java 5. > It's the reason why there is no ThrowableConsumer, as an example, > imagine that a stream can declare a checked exception Stream and > a user call map() that takes a ThrowableFunction, > we need a way to express that the resulting stream is that combine the > exceptions of the original stream and the exceptions that may be > raised by calling the function of map. > > ? Stream? --> map(ThrowableFunction extends Exception>) -->? Stream > > Or perhaps from the beginning of Java, adding a checked exception to a > "throws" colors the function the same way the keyword async or Rust > lifetime type information color a function [1]. Adding a checked > exception to a function is not a backward compatible change. > > So we have some of idioms that beginners need to internalize to try > workaround checked exceptions, > - The oldest is i think, Thread.currentThread().interrupt() which > allows to silence an InterruptedException at the price of continuing > to execute the code until the next blocking call > - UncheckedIOException and IOError that both wrap an IOException into > an unchecked exception allowing tunneling of checked exceptions ; > wrapping an IOException and unbundle it later. > - Unsafe.rethrow (this one was retired) > - the unfamous rethrow using erasure to see a checked exception as an > unchecked exception > ?? static AssertionError rethrow(Throwable > cause) throws T { > ????? throw (T) cause; > ?? } > - IntelliJ has changed the default try/catch snippet to instead of > calling printStackTrace() to throw a RuntimeException wrapping the > exception. > ? This simple change is i believe the best change to Java in the > recent years (perhaps toes to toes with records), at least now the > code of my students does not print the stack trace and resume its > course when an exception occurs. > ??? try { > ???? ... > ??? } catch(FooException e) { > ??? ? throw new RuntimeException(e); > ??? } > > Also no language presented as potential successor of Java, neither > Scala nor Kotlin have checked exceptions, because functions with > checked exceptions do not compose. > If Java wants to be the next Java, we will have to drop checked > exceptions at some point. > > The good news is that seeing all exceptions as unchecked exceptions is > a backward compatible change, "throws" can still be supported for > documentation purpose, the compiler can emit a warning instead of an > error if there is no catch corresponding to a checked exception and > allow everyone to catch any exceptions in the code. > > I think we should recognize that the idea of checked exceptions was a > good idea on paper but not a good one in practice and work to retire > the concept of checked exceptions from Java. > > R?mi > > [1] > https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ > > ------------------------------------------------------------------------ > > *From: *"Nathan Reynolds" > *To: *"amber-dev" > *Sent: *Saturday, November 12, 2022 5:47:10 AM > *Subject: *Throwing Functions > > I am sorry if I am very late to the discussion. Consumer, > Function, Predicate, and Supplier don't allow for throwing checked > exceptions.? This feature is needed in many cases.? What about > adding a variant that allows for throwing checked exceptions?? For > example, a ThrowableConsumer could be defined as such... > > public interface ThrowableConsumer > { > ?? void accept(T t) throws E; > } > > A method that receives this as a parameter could be defined as such... > > public void process(ThrowableConsumer > consume) throws E > { > ?? ... > } > > The compiler takes care of ensuring the checked exception is dealt > with in the caller to process(). > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Sat Nov 12 16:22:14 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 12 Nov 2022 11:22:14 -0500 Subject: Retiring Checked Exceptions Was: Throwing Functions In-Reply-To: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> References: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> Message-ID: <500d565c-6281-40ba-930c-812cf4693707@oracle.com> Counter-proposal: let's just retire the endless stream of "let's just get rid of checked exceptions" proposals instead. This is all well-traveled ground, and has all been brought up before (including by you several times.)? I get how attractive it is to "just" declare checked exceptions a mistake.? But even if it was, we know that trying to "fix" the "mistakes" of the past often only makes things worse. There is interesting research going on in the Scala community and elsewhere about better treatment of effects; some of this may bear fruit that might be a better approach than the "just uncheck them all."? In any case, I'm not interested in reopening this discussion at this time; we have plenty else on the priority list. Verdict: Motion Denied.? Leave is granted to refile your motion in 2025. On 11/12/2022 2:58 AM, Remi Forax wrote: > [promoted to amber-spec-experts] > > I think we should tackle this problem at its core and retire the > notion of checked exceptions > > The written are on the wall since quite some time, but we have not yet > acknowledge it. > > Let's recap the issue and the clues pointing in that direction. > > I believe the first straw can be tracked back to the inability of the > type system to create a type variable containing the union of > exceptions when generics where introduced in Java 5. > It's the reason why there is no ThrowableConsumer, as an example, > imagine that a stream can declare a checked exception Stream and > a user call map() that takes a ThrowableFunction, > we need a way to express that the resulting stream is that combine the > exceptions of the original stream and the exceptions that may be > raised by calling the function of map. > > ? Stream? --> map(ThrowableFunction extends Exception>) -->? Stream > > Or perhaps from the beginning of Java, adding a checked exception to a > "throws" colors the function the same way the keyword async or Rust > lifetime type information color a function [1]. Adding a checked > exception to a function is not a backward compatible change. > > So we have some of idioms that beginners need to internalize to try > workaround checked exceptions, > - The oldest is i think, Thread.currentThread().interrupt() which > allows to silence an InterruptedException at the price of continuing > to execute the code until the next blocking call > - UncheckedIOException and IOError that both wrap an IOException into > an unchecked exception allowing tunneling of checked exceptions ; > wrapping an IOException and unbundle it later. > - Unsafe.rethrow (this one was retired) > - the unfamous rethrow using erasure to see a checked exception as an > unchecked exception > ?? static AssertionError rethrow(Throwable > cause) throws T { > ????? throw (T) cause; > ?? } > - IntelliJ has changed the default try/catch snippet to instead of > calling printStackTrace() to throw a RuntimeException wrapping the > exception. > ? This simple change is i believe the best change to Java in the > recent years (perhaps toes to toes with records), at least now the > code of my students does not print the stack trace and resume its > course when an exception occurs. > ??? try { > ???? ... > ??? } catch(FooException e) { > ??? ? throw new RuntimeException(e); > ??? } > > Also no language presented as potential successor of Java, neither > Scala nor Kotlin have checked exceptions, because functions with > checked exceptions do not compose. > If Java wants to be the next Java, we will have to drop checked > exceptions at some point. > > The good news is that seeing all exceptions as unchecked exceptions is > a backward compatible change, "throws" can still be supported for > documentation purpose, the compiler can emit a warning instead of an > error if there is no catch corresponding to a checked exception and > allow everyone to catch any exceptions in the code. > > I think we should recognize that the idea of checked exceptions was a > good idea on paper but not a good one in practice and work to retire > the concept of checked exceptions from Java. > > R?mi > > [1] > https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ > > ------------------------------------------------------------------------ > > *From: *"Nathan Reynolds" > *To: *"amber-dev" > *Sent: *Saturday, November 12, 2022 5:47:10 AM > *Subject: *Throwing Functions > > I am sorry if I am very late to the discussion. Consumer, > Function, Predicate, and Supplier don't allow for throwing checked > exceptions.? This feature is needed in many cases.? What about > adding a variant that allows for throwing checked exceptions?? For > example, a ThrowableConsumer could be defined as such... > > public interface ThrowableConsumer > { > ?? void accept(T t) throws E; > } > > A method that receives this as a parameter could be defined as such... > > public void process(ThrowableConsumer > consume) throws E > { > ?? ... > } > > The compiler takes care of ensuring the checked exception is dealt > with in the caller to process(). > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Sat Nov 12 22:50:17 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 12 Nov 2022 17:50:17 -0500 Subject: Retiring Checked Exceptions Was: Throwing Functions In-Reply-To: References: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> Message-ID: I appreciate John's points here.? I don't necessarily agree with all of them (there's a spectrum of opinions, and that's fine, though I find #3 especially compelling), but I think this illustrates something about the exceptions debate that is easy to miss: the people who hate checked exceptions are much noisier about it than those who don't, and so they are likely to be fooled by confirmation bias since all the other loud voices seem to agree with them.? But I've found that there are a lot of people out there who quietly think checked exceptions are ... pretty OK.? Maybe even a majority.? They just don't want to engage in a big debate, they'd rather get their work done. On 11/12/2022 11:16 AM, John Hendrikx wrote: > I very much disagree with this position, so I will make a case for > checked exceptions: > > 1) Without checked exceptions, using exceptions for alternative > outcomes as part of the contract of an API would no longer be > possible. This is because adding a new exception to the API would no > longer be a breaking change. Documentation is not going to save you > here.? Effectively, exceptions would have only two uses left (like in > other languages): fatal JVM breaking errors and to signal mistakes > that could have been prevented by the programmer.? Using them to > signal unpreventable errors would be highly suspect and likely quickly > be considered a bad practice. > > In other languages (but also in some Java API's that use runtime > exception to signal unpreventable errors) the compiler cannot help you > with these alternative outcomes as it isn't even required to specify > them as part of your API. It helps you with the return value, but not > for any other outcomes. These other outcomes will now have to guessed, > gleaned from the documentation (if it is up to date), or by doing > manual code mining (of the called function and all the functions it > calls).? Worse, these outcomes can change in later releases without > any warning as they're non-breaking changes. > > 2) API's without checked exceptions will necessarily become more > cluttered than their counterparts with checked exceptions. They would > have to return wrappers or unions or special values to enforce proper > use. API design like this prevents easily deferring the handling of > rare occurrences higher up the call chain with standard idioms to keep > the current code path clean and to the point. > > 3) Removing checked exceptions now would break the **design** of many > current API's, making them dangerous to use without the checks and > balances that were present when they were designed. > > 4) Earlier design decisions to exclude checked exceptions from new > idioms and API's were a mistake that should be rectified not doubled > down upon. A large part of the momentum against checked exceptions > comes from the clumsy way that checked exceptions must be handled > while using these new features that were essentially incompatible with > existing Java.? Even with the current status quo, it is possible to > design API's that do allow checked exceptions in combination with > functional programming, it is just cumbersome to design these API's > without a dedicated union type (for exceptions).? They either support > only one checked exception or some limited number.? Their use is > however as transparent as API's that do not support checked exceptions. > > 5) The fact that the value of checked exceptions is hard to recognize > or cumbersome for beginners or non-Java developers should not have any > bearing on language design. > > Checked exceptions differentiate between the common preventable > programming errors and essential business logic. The difference > between a runtime exception (leaving out Error) and a checked > exception is that one can only occur in incorrect code, while the > other can occur even in correct code. One indicates a preventable > programming mistake and the other a missed path in your logic.? > Throwing these on the same heap will effectively reduce the usefulness > of all exceptions to programming mistakes (and fatal errors) only. > > 6) If anything, I think there should be way to promote runtime > exceptions to checked exceptions within certain modules.? This would > allow API / library designers the option to have the compiler check > their code for missed documentation and missing logic even for what > externally would be a runtime exception.? This would be especially > useful during initial design and also later refactoring as the > incredibly useful compiler checks for checked exceptions could be > extended to proper use and propagation of runtime exceptions within > that module. > > --John > > > ------ Original Message ------ > From "Remi Forax" > To "Nathan Reynolds" > Cc "amber-dev" ; "amber-spec-experts" > ; "Ron Pressler" > > Date 12/11/2022 08:58:57 > Subject Retiring Checked Exceptions Was: Throwing Functions > >> [promoted to amber-spec-experts] >> >> I think we should tackle this problem at its core and retire the >> notion of checked exceptions >> >> The written are on the wall since quite some time, but we have not >> yet acknowledge it. >> >> Let's recap the issue and the clues pointing in that direction. >> >> I believe the first straw can be tracked back to the inability of the >> type system to create a type variable containing the union of >> exceptions when generics where introduced in Java 5. >> It's the reason why there is no ThrowableConsumer, as an example, >> imagine that a stream can declare a checked exception Stream >> and a user call map() that takes a ThrowableFunction, >> we need a way to express that the resulting stream is that combine >> the exceptions of the original stream and the exceptions that may be >> raised by calling the function of map. >> >> ? Stream? --> map(ThrowableFunction> extends Exception>) -->? Stream >> >> Or perhaps from the beginning of Java, adding a checked exception to >> a "throws" colors the function the same way the keyword async or Rust >> lifetime type information color a function [1]. Adding a checked >> exception to a function is not a backward compatible change. >> >> So we have some of idioms that beginners need to internalize to try >> workaround checked exceptions, >> - The oldest is i think, Thread.currentThread().interrupt() which >> allows to silence an InterruptedException at the price of continuing >> to execute the code until the next blocking call >> - UncheckedIOException and IOError that both wrap an IOException into >> an unchecked exception allowing tunneling of checked exceptions ; >> wrapping an IOException and unbundle it later. >> - Unsafe.rethrow (this one was retired) >> - the unfamous rethrow using erasure to see a checked exception as an >> unchecked exception >> ?? static AssertionError rethrow(Throwable >> cause) throws T { >> ????? throw (T) cause; >> ?? } >> - IntelliJ has changed the default try/catch snippet to instead of >> calling printStackTrace() to throw a RuntimeException wrapping the >> exception. >> ? This simple change is i believe the best change to Java in the >> recent years (perhaps toes to toes with records), at least now the >> code of my students does not print the stack trace and resume its >> course when an exception occurs. >> ??? try { >> ???? ... >> ??? } catch(FooException e) { >> ??? ? throw new RuntimeException(e); >> ??? } >> >> Also no language presented as potential successor of Java, neither >> Scala nor Kotlin have checked exceptions, because functions with >> checked exceptions do not compose. >> If Java wants to be the next Java, we will have to drop checked >> exceptions at some point. > I don't see the relevance of what other languages are doing with their > own agenda's. There is no need to drop checked exceptions, they just > need to be an integral part of the whole. Removing them doesn't make > Java the next Java, it just makes it yet another language with > slightly different syntax that succumbed to a vocal minority that > values simplicity over safety. > >> The good news is that seeing all exceptions as unchecked exceptions >> is a backward compatible change, "throws" can still be supported for >> documentation purpose, the compiler can emit a warning instead of an >> error if there is no catch corresponding to a checked exception and >> allow everyone to catch any exceptions in the code. > >> >> >> I think we should recognize that the idea of checked exceptions was a >> good idea on paper but not a good one in practice and work to retire >> the concept of checked exceptions from Java. >> >> R?mi >> >> [1] >> https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ >> >> ------------------------------------------------------------------------ >> >> *From: *"Nathan Reynolds" >> *To: *"amber-dev" >> *Sent: *Saturday, November 12, 2022 5:47:10 AM >> *Subject: *Throwing Functions >> >> I am sorry if I am very late to the discussion. Consumer, >> Function, Predicate, and Supplier don't allow for throwing >> checked exceptions.? This feature is needed in many cases.? What >> about adding a variant that allows for throwing checked >> exceptions?? For example, a ThrowableConsumer could be defined as >> such... >> >> public interface ThrowableConsumer >> { >> ?? void accept(T t) throws E; >> } >> >> A method that receives this as a parameter could be defined as >> such... >> >> public void process(ThrowableConsumer >> consume) throws E >> { >> ?? ... >> } >> >> The compiler takes care of ensuring the checked exception is >> dealt with in the caller to process(). >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Mon Nov 14 12:38:46 2022 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Mon, 14 Nov 2022 12:38:46 +0000 Subject: Late change to JEP 433 In-Reply-To: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> Message-ID: Dear Experts, As we put the final polish on features for JDK20, we noticed that we have an opportunity to make a very small breaking change (as part of the preview feature) to simplify our lives. I?m writing to see what you think. tldr: A switch expression over an enum class should throw MatchException rather than IncompatibleClassChangeError if no switch label applies at runtime. Details: When we introduced switch expressions, we opted for a design where the switch body had to be exhaustive. When switching over an enum type, a switch body with case labels supporting all the enum constants for the enum type is considered exhaustive, meaning a default clause is not needed. However, there is a possibility that the enum class is changed after compilation of the switch expression, and a new enum constant added. Then when executing the switchexpression, no label would apply. The question we faced in JDK14 was what to do at this point. We decided on IncompatibleClassChangeError as that was a pre-existing exception that was generally understood by developers as a signal that things have got out of sync and re-compilation is needed. Back to the present day, with the support of pattern switches, we can now write switches over a sealed type. When switching over a sealed type, a switch body with case labels with type patterns matching all the permitted subclasses is considered exhaustive, meaning a default clause is not needed. If the sealed hierarchy has been changed after compilation of the switch, it is possible that when executing the switch that no label would apply. In this case we have settled on throwing a MatchException. Throughout our design process, we have noticed the connection between enum classes/enum constants and sealed class/permitted subclasses ? they are essentially the same thing up the term/type hierarchy. Moreover, in a future release, we plan to support case labels with a mix of sealed class type patterns and enum constants. But we now have an inconsistency - one throws IncompatibleClassChangeException in a bad situation and the other MatchException which will make this future development almost impossible. We need these cases to throw the same exception: MatchException. So we propose to make the small breaking case to the language that switch expressions over enum classes throw MatchException should no switch label apply in the switch body. People who deliberately change their enum classes by adding new constants, and do not recompile their switches over this enum class, and rely on this throwing ICCE will notice this breaking change. We think this is a vanishingly small set of developers. The vast majority of developers, on the other hand, will thank us for this unification, especially if it enables other new features down the road. What do you think? Thanks, Gavin From brian.goetz at oracle.com Mon Nov 14 17:54:55 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 14 Nov 2022 12:54:55 -0500 Subject: Retiring Checked Exceptions Was: Throwing Functions In-Reply-To: References: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> Message-ID: On 11/14/2022 11:33 AM, Archie Cobbs wrote: > > I like checked exceptions also. I think the replies here have proven my point. It's an easy opinion to say "checked exceptions were a failed experiment" -- likely too-easy an opinion -- but people have a right to their opinions. But even if one conceded this point, that doesn't mean "so back it out" is a smart move.? People have built up billions of lines of code based on assumptions about how exceptions work; pulling the rug out from under them has a real and pervasive cost.? Banging the "failed experiment" drum incorrectly assumes those costs away. But more importantly, the "failed experiment" crowd seems to take it as an article of faith that everyone agrees with them, because there are not protest rallies in the street chanting "Save Checked Exceptions".? But it did not take long to elicit a few well-reasoned "I prefer the status quo" opinions.? There are plenty of people who think the status quo is fine, and that a radical change would be worse, they're just not making a big deal about it, instead they're getting work done. Yes, it is unfortunate that some early JDK APIs used checked exceptions poorly, before we really understood what they were good and bad for.? And yes, its unfortunate that they have inconvenient interactions with other language features, such as lambdas. Another aspect of the unhelpfulness of the "let's just kill them" argument is that Nathan's modest request gets lost in the shuffle. Nathan came with a reasonable request -- "can we have a few more functional interfaces" -- and instead, someone used it as an excuse to start a holy war and reasonable mitigations easily get lost along the way. -------------- next part -------------- An HTML attachment was scrubbed... URL: From alex.buckley at oracle.com Mon Nov 14 18:56:35 2022 From: alex.buckley at oracle.com (Alex Buckley) Date: Mon, 14 Nov 2022 10:56:35 -0800 Subject: Late change to JEP 433 In-Reply-To: References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> Message-ID: <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> I always liked Kevin's commentary on how the underlying cause of an unrecognized enum constant was classpath misconfiguration arising from inconsistent separate compilation. Still, the use by switch expressions of ICCE (a LinkageError) was irregular because it was the _only place_ where the Java language actively handled inconsistent separate compilation. All the other LinkageErrors in the JLS merely reflect what the JVM does when inconsistent separate compilation leads to linking failures. For example, 8.1.4 says "If circularly declared classes are detected at run time, as classes are loaded, then a ClassCircularityError is thrown (?12.2.1)." where 12.2.1 presents JVM behavior from the viewpoint of the Java language. The JVM throws its LinkageErrors regardless of the source language, of course, so the JLS explicitly "adopting" a LinkageError in the rules for switch expressions was a bit "raw". I'm glad that pattern matching has evolved to the point where ICCE can hand over to MatchException, whose shape in Java 20 could not reasonably have been foreseen in Java 12-14. Dropping the use of ICCE in switch expressions leaves AssertionError in 14.10 as the only Error mandated by the Java language itself. That's appropriate, since an assertion failure lies in the plane of the program. Assertion failures have some extra-lingual flavor (being enabled from outside the program) but are still very different than the plethora of extra-lingual failures arising from inconsistent separate compilation and reported as LinkageErrors. (I think JLS 11.1.2 "The Causes of Exceptions" ought to mention an `assert` statement -- filed https://bugs.openjdk.org/browse/JDK-8296951) Alex On 11/14/2022 4:38 AM, Gavin Bierman wrote: > Dear Experts, > > As we put the final polish on features for JDK20, we noticed that we have an opportunity to make a very small breaking change (as part of the preview feature) to simplify our lives. I?m writing to see what you think. > > tldr: A switch expression over an enum class should throw MatchException rather than IncompatibleClassChangeError if no switch label applies at runtime. > > Details: > > When we introduced switch expressions, we opted for a design where the switch body had to be exhaustive. When switching over an enum type, a switch body with case labels supporting all the enum constants for the enum type is considered exhaustive, meaning a default clause is not needed. > > However, there is a possibility that the enum class is changed after compilation of the switch expression, and a new enum constant added. Then when executing the switchexpression, no label would apply. > > The question we faced in JDK14 was what to do at this point. We decided on IncompatibleClassChangeError as that was a pre-existing exception that was generally understood by developers as a signal that things have got out of sync and re-compilation is needed. > > Back to the present day, with the support of pattern switches, we can now write switches over a sealed type. When switching over a sealed type, a switch body with case labels with type patterns matching all the permitted subclasses is considered exhaustive, meaning a default clause is not needed. > > If the sealed hierarchy has been changed after compilation of the switch, it is possible that when executing the switch that no label would apply. In this case we have settled on throwing a MatchException. > > Throughout our design process, we have noticed the connection between enum classes/enum constants and sealed class/permitted subclasses ? they are essentially the same thing up the term/type hierarchy. Moreover, in a future release, we plan to support case labels with a mix of sealed class type patterns and enum constants. > > But we now have an inconsistency - one throws IncompatibleClassChangeException in a bad situation and the other MatchException which will make this future development almost impossible. We need these cases to throw the same exception: MatchException. So we propose to make the small breaking case to the language that switch expressions over enum classes throw MatchException should no switch label apply in the switch body. > > People who deliberately change their enum classes by adding new constants, and do not recompile their switches over this enum class, and rely on this throwing ICCE will notice this breaking change. We think this is a vanishingly small set of developers. The vast majority of developers, on the other hand, will thank us for this unification, especially if it enables other new features down the road. > > What do you think? > > Thanks, > Gavin From kevinb at google.com Mon Nov 14 19:14:26 2022 From: kevinb at google.com (Kevin Bourrillion) Date: Mon, 14 Nov 2022 11:14:26 -0800 Subject: Late change to JEP 433 In-Reply-To: References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> Message-ID: Makes complete sense to me. A switch that was acceptably exhaustive when it was compiled can still get an unhandleable value at runtime for I think a small handful of different reasons, and with your change they would all throw the same thing, correct? I don't fully remember the points I made about ICCError, but surely this overrides them! On Mon, Nov 14, 2022 at 4:38 AM Gavin Bierman wrote: > Dear Experts, > > As we put the final polish on features for JDK20, we noticed that we have > an opportunity to make a very small breaking change (as part of the preview > feature) to simplify our lives. I?m writing to see what you think. > > tldr: A switch expression over an enum class should throw MatchException > rather than IncompatibleClassChangeError if no switch label applies at > runtime. > > Details: > > When we introduced switch expressions, we opted for a design where the > switch body had to be exhaustive. When switching over an enum type, a > switch body with case labels supporting all the enum constants for the enum > type is considered exhaustive, meaning a default clause is not needed. > > However, there is a possibility that the enum class is changed after > compilation of the switch expression, and a new enum constant added. Then > when executing the switchexpression, no label would apply. > > The question we faced in JDK14 was what to do at this point. We decided on > IncompatibleClassChangeError as that was a pre-existing exception that was > generally understood by developers as a signal that things have got out of > sync and re-compilation is needed. > > Back to the present day, with the support of pattern switches, we can now > write switches over a sealed type. When switching over a sealed type, a > switch body with case labels with type patterns matching all the permitted > subclasses is considered exhaustive, meaning a default clause is not needed. > > If the sealed hierarchy has been changed after compilation of the switch, > it is possible that when executing the switch that no label would apply. In > this case we have settled on throwing a MatchException. > > Throughout our design process, we have noticed the connection between enum > classes/enum constants and sealed class/permitted subclasses ? they are > essentially the same thing up the term/type hierarchy. Moreover, in a > future release, we plan to support case labels with a mix of sealed class > type patterns and enum constants. > > But we now have an inconsistency - one throws > IncompatibleClassChangeException in a bad situation and the other > MatchException which will make this future development almost impossible. > We need these cases to throw the same exception: MatchException. So we > propose to make the small breaking case to the language that switch > expressions over enum classes throw MatchException should no switch label > apply in the switch body. > > People who deliberately change their enum classes by adding new constants, > and do not recompile their switches over this enum class, and rely on this > throwing ICCE will notice this breaking change. We think this is a > vanishingly small set of developers. The vast majority of developers, on > the other hand, will thank us for this unification, especially if it > enables other new features down the road. > > What do you think? > > Thanks, > Gavin -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Mon Nov 14 19:24:04 2022 From: john.r.rose at oracle.com (John Rose) Date: Mon, 14 Nov 2022 11:24:04 -0800 Subject: Late change to JEP 433 In-Reply-To: <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> Message-ID: <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> On 14 Nov 2022, at 10:56, Alex Buckley wrote: > ? ICCE can hand over to MatchException ? Precisely; I agree that it is time for this to happen. Thanks, Alex for reminding us of the history and lineage of ICCE, and why it doesn?t make sense for switch statements (not even classic switch-over-enum). As a program linkage error, ICCE is necessarily uncommunicative when applied to a misconfigured switch statement. Using a MatchError is on the other hand highly informative: The user (and possibly try/catch logic surrounding the failure) knows exactly what happened, that a set of matches expected to succeed has failed. So, here?s a possible knock-on advantage if we hand off from ICCE to ME: If there is further development of the concept of ?a set of matches which is required to succeed?, the error processing can continue to be unified under the ME. Brian?s ideas about ?let-statements? entail a single pattern which is required to match; ME is surely the right way to signal failure (if not something more specific like CCE or NPE, which is an interesting side-conversation). Or, if we ever did Haskell-style method overloads that discriminate arguments by means of patterns, surely they would desugar to omnibus methods that start with switches; once again ME surely makes sense as a way to signal inapplicability of such match-based methods. ? John P.S. More speculatively, and probably a bridge too far, would be to employ MatchException as a part of a meta-language protocol that defines how sets of patterns compose, and in particular how one part of a composite signals failure to the whole composite. (Surely there is some future use for X in methods : method handles :: patterns : X; that?s what I mean by a meta-language protocol.) I say this is a bridge too far because Java exceptions are not a very good tool for normally-frequent control flow, and also because ME, like NPE or CCE, probably best signals a failure of the programmer?s settled intentions about some code, rather than signaling an alternative control path (like if/else). Still, I wanted to point this out because in other languages exception-like concepts are used to convey backtracking out of composite control flow patterns, and if we decided to try this out for Java, MatchExpression would raise its hand and say ?pick me!? From brian.goetz at oracle.com Mon Nov 14 20:01:27 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 14 Nov 2022 15:01:27 -0500 Subject: Late change to JEP 433 In-Reply-To: <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> Message-ID: <44092984-7a99-e0e9-0510-90a84ce68002@oracle.com> > Precisely; I agree that it is time for this to happen. Thanks, Alex for reminding us of the history and lineage of ICCE, and why it doesn?t make sense for switch statements (not even classic switch-over-enum). To throw another log on this fire, at some point, we'd like to treat switch-over-enum as just another pattern switch, not a bespoke form of switch. From forax at univ-mlv.fr Mon Nov 14 22:23:01 2022 From: forax at univ-mlv.fr (Remi Forax) Date: Mon, 14 Nov 2022 23:23:01 +0100 (CET) Subject: Late change to JEP 433 In-Reply-To: References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> Message-ID: <1583477832.45460655.1668464581914.JavaMail.zimbra@u-pem.fr> Does someone has done the work to check if there are a few?, some?, a lot? of codes that catch IncompatibleClassChangeError in the wild ? Because replacing a exception by another usually leads to subtle bugs, especially when an Error which is replaced by an RuntimeException. Sadly catch(RuntimeException) / catch(Exception) are the usual trouble makers. R?mi ----- Original Message ----- > From: "Gavin Bierman" > To: "amber-spec-experts" > Sent: Monday, November 14, 2022 1:38:46 PM > Subject: Late change to JEP 433 > Dear Experts, > > As we put the final polish on features for JDK20, we noticed that we have an > opportunity to make a very small breaking change (as part of the preview > feature) to simplify our lives. I?m writing to see what you think. > > tldr: A switch expression over an enum class should throw MatchException rather > than IncompatibleClassChangeError if no switch label applies at runtime. > > Details: > > When we introduced switch expressions, we opted for a design where the switch > body had to be exhaustive. When switching over an enum type, a switch body with > case labels supporting all the enum constants for the enum type is considered > exhaustive, meaning a default clause is not needed. > > However, there is a possibility that the enum class is changed after compilation > of the switch expression, and a new enum constant added. Then when executing > the switchexpression, no label would apply. > > The question we faced in JDK14 was what to do at this point. We decided on > IncompatibleClassChangeError as that was a pre-existing exception that was > generally understood by developers as a signal that things have got out of sync > and re-compilation is needed. > > Back to the present day, with the support of pattern switches, we can now write > switches over a sealed type. When switching over a sealed type, a switch body > with case labels with type patterns matching all the permitted subclasses is > considered exhaustive, meaning a default clause is not needed. > > If the sealed hierarchy has been changed after compilation of the switch, it is > possible that when executing the switch that no label would apply. In this case > we have settled on throwing a MatchException. > > Throughout our design process, we have noticed the connection between enum > classes/enum constants and sealed class/permitted subclasses ? they are > essentially the same thing up the term/type hierarchy. Moreover, in a future > release, we plan to support case labels with a mix of sealed class type > patterns and enum constants. > > But we now have an inconsistency - one throws IncompatibleClassChangeException > in a bad situation and the other MatchException which will make this future > development almost impossible. We need these cases to throw the same exception: > MatchException. So we propose to make the small breaking case to the language > that switch expressions over enum classes throw MatchException should no switch > label apply in the switch body. > > People who deliberately change their enum classes by adding new constants, and > do not recompile their switches over this enum class, and rely on this throwing > ICCE will notice this breaking change. We think this is a vanishingly small set > of developers. The vast majority of developers, on the other hand, will thank > us for this unification, especially if it enables other new features down the > road. > > What do you think? > > Thanks, > Gavin From forax at univ-mlv.fr Mon Nov 14 22:31:57 2022 From: forax at univ-mlv.fr (Remi Forax) Date: Mon, 14 Nov 2022 23:31:57 +0100 (CET) Subject: Late change to JEP 433 In-Reply-To: <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> Message-ID: <842334026.45461578.1668465117769.JavaMail.zimbra@u-pem.fr> I'm confused, is it MatchError or MatchException ? Because if it's an error instead of an exception, it may be less an issue in term of backward compatibility but it is not what is proposed, right ? R?mi ----- Original Message ----- > From: "John Rose" > To: "Alex Buckley" > Cc: "amber-spec-experts" > Sent: Monday, November 14, 2022 8:24:04 PM > Subject: Re: Late change to JEP 433 > On 14 Nov 2022, at 10:56, Alex Buckley wrote: > >> ? ICCE can hand over to MatchException ? > > Precisely; I agree that it is time for this to happen. Thanks, Alex for > reminding us of the history and lineage of ICCE, and why it doesn?t make sense > for switch statements (not even classic switch-over-enum). > > As a program linkage error, ICCE is necessarily uncommunicative when applied to > a misconfigured switch statement. Using a MatchError is on the other hand > highly informative: The user (and possibly try/catch logic surrounding the > failure) knows exactly what happened, that a set of matches expected to succeed > has failed. > > So, here?s a possible knock-on advantage if we hand off from ICCE to ME: If > there is further development of the concept of ?a set of matches which is > required to succeed?, the error processing can continue to be unified under the > ME. Brian?s ideas about ?let-statements? entail a single pattern which is > required to match; ME is surely the right way to signal failure (if not > something more specific like CCE or NPE, which is an interesting > side-conversation). Or, if we ever did Haskell-style method overloads that > discriminate arguments by means of patterns, surely they would desugar to > omnibus methods that start with switches; once again ME surely makes sense as a > way to signal inapplicability of such match-based methods. > > ? John > > P.S. More speculatively, and probably a bridge too far, would be to employ > MatchException as a part of a meta-language protocol that defines how sets of > patterns compose, and in particular how one part of a composite signals failure > to the whole composite. (Surely there is some future use for X in methods : > method handles :: patterns : X; that?s what I mean by a meta-language > protocol.) I say this is a bridge too far because Java exceptions are not a > very good tool for normally-frequent control flow, and also because ME, like > NPE or CCE, probably best signals a failure of the programmer?s settled > intentions about some code, rather than signaling an alternative control path > (like if/else). Still, I wanted to point this out because in other languages > exception-like concepts are used to convey backtracking out of composite > control flow patterns, and if we decided to try this out for Java, > MatchExpression would raise its hand and say ?pick me!? From brian.goetz at oracle.com Mon Nov 14 22:40:27 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 14 Nov 2022 17:40:27 -0500 Subject: Late change to JEP 433 In-Reply-To: <842334026.45461578.1668465117769.JavaMail.zimbra@u-pem.fr> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> <842334026.45461578.1668465117769.JavaMail.zimbra@u-pem.fr> Message-ID: <94e5524b-ffde-7af0-e7c8-f7d659fc1a89@oracle.com> Its MatchException.? Error would not be appropriate, since this is the same exception that gets used for remainder (e.g., Box(Box(var x)) against a target of Box(null)). On 11/14/2022 5:31 PM, Remi Forax wrote: > I'm confused, is it MatchError or MatchException ? > > Because if it's an error instead of an exception, it may be less an issue in term of backward compatibility but it is not what is proposed, right ? > > R?mi > > ----- Original Message ----- >> From: "John Rose" >> To: "Alex Buckley" >> Cc: "amber-spec-experts" >> Sent: Monday, November 14, 2022 8:24:04 PM >> Subject: Re: Late change to JEP 433 >> On 14 Nov 2022, at 10:56, Alex Buckley wrote: >> >>> ? ICCE can hand over to MatchException ? >> Precisely; I agree that it is time for this to happen. Thanks, Alex for >> reminding us of the history and lineage of ICCE, and why it doesn?t make sense >> for switch statements (not even classic switch-over-enum). >> >> As a program linkage error, ICCE is necessarily uncommunicative when applied to >> a misconfigured switch statement. Using a MatchError is on the other hand >> highly informative: The user (and possibly try/catch logic surrounding the >> failure) knows exactly what happened, that a set of matches expected to succeed >> has failed. >> >> So, here?s a possible knock-on advantage if we hand off from ICCE to ME: If >> there is further development of the concept of ?a set of matches which is >> required to succeed?, the error processing can continue to be unified under the >> ME. Brian?s ideas about ?let-statements? entail a single pattern which is >> required to match; ME is surely the right way to signal failure (if not >> something more specific like CCE or NPE, which is an interesting >> side-conversation). Or, if we ever did Haskell-style method overloads that >> discriminate arguments by means of patterns, surely they would desugar to >> omnibus methods that start with switches; once again ME surely makes sense as a >> way to signal inapplicability of such match-based methods. >> >> ? John >> >> P.S. More speculatively, and probably a bridge too far, would be to employ >> MatchException as a part of a meta-language protocol that defines how sets of >> patterns compose, and in particular how one part of a composite signals failure >> to the whole composite. (Surely there is some future use for X in methods : >> method handles :: patterns : X; that?s what I mean by a meta-language >> protocol.) I say this is a bridge too far because Java exceptions are not a >> very good tool for normally-frequent control flow, and also because ME, like >> NPE or CCE, probably best signals a failure of the programmer?s settled >> intentions about some code, rather than signaling an alternative control path >> (like if/else). Still, I wanted to point this out because in other languages >> exception-like concepts are used to convey backtracking out of composite >> control flow patterns, and if we decided to try this out for Java, >> MatchExpression would raise its hand and say ?pick me!? -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Mon Nov 14 22:51:19 2022 From: john.r.rose at oracle.com (John Rose) Date: Mon, 14 Nov 2022 14:51:19 -0800 Subject: Late change to JEP 433 In-Reply-To: <94e5524b-ffde-7af0-e7c8-f7d659fc1a89@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> <842334026.45461578.1668465117769.JavaMail.zimbra@u-pem.fr> <94e5524b-ffde-7af0-e7c8-f7d659fc1a89@oracle.com> Message-ID: <2D23BB8C-0346-4B56-BA85-BCC65B84649F@oracle.com> My bad; I thought <:RuntimeException and wrote <:Error. On 14 Nov 2022, at 14:40, Brian Goetz wrote: > Its MatchException.? Error would not be appropriate, since this is > the same exception that gets used for remainder (e.g., Box(Box(var x)) > against a target of Box(null)). > > On 11/14/2022 5:31 PM, Remi Forax wrote: >> I'm confused, is it MatchError or MatchException ? >> >> Because if it's an error instead of an exception, it may be less an >> issue in term of backward compatibility but it is not what is >> proposed, right ? >> >> R?mi >> >> ----- Original Message ----- >>> From: "John Rose" >>> To: "Alex Buckley" >>> Cc: "amber-spec-experts" >>> Sent: Monday, November 14, 2022 8:24:04 PM >>> Subject: Re: Late change to JEP 433 >>> On 14 Nov 2022, at 10:56, Alex Buckley wrote: >>> >>>> ? ICCE can hand over to MatchException ? >>> Precisely; I agree that it is time for this to happen. Thanks, Alex >>> for >>> reminding us of the history and lineage of ICCE, and why it >>> doesn?t make sense >>> for switch statements (not even classic switch-over-enum). >>> >>> As a program linkage error, ICCE is necessarily uncommunicative when >>> applied to >>> a misconfigured switch statement. Using a MatchError is on the >>> other hand >>> highly informative: The user (and possibly try/catch logic >>> surrounding the >>> failure) knows exactly what happened, that a set of matches expected >>> to succeed >>> has failed. >>> >>> So, here?s a possible knock-on advantage if we hand off from ICCE >>> to ME: If >>> there is further development of the concept of ?a set of matches >>> which is >>> required to succeed?, the error processing can continue to be >>> unified under the >>> ME. Brian?s ideas about ?let-statements? entail a single >>> pattern which is >>> required to match; ME is surely the right way to signal failure (if >>> not >>> something more specific like CCE or NPE, which is an interesting >>> side-conversation). Or, if we ever did Haskell-style method >>> overloads that >>> discriminate arguments by means of patterns, surely they would >>> desugar to >>> omnibus methods that start with switches; once again ME surely makes >>> sense as a >>> way to signal inapplicability of such match-based methods. >>> >>> ? John >>> >>> P.S. More speculatively, and probably a bridge too far, would be to >>> employ >>> MatchException as a part of a meta-language protocol that defines >>> how sets of >>> patterns compose, and in particular how one part of a composite >>> signals failure >>> to the whole composite. (Surely there is some future use for X in >>> methods : >>> method handles :: patterns : X; that?s what I mean by a >>> meta-language >>> protocol.) I say this is a bridge too far because Java exceptions >>> are not a >>> very good tool for normally-frequent control flow, and also because >>> ME, like >>> NPE or CCE, probably best signals a failure of the programmer?s >>> settled >>> intentions about some code, rather than signaling an alternative >>> control path >>> (like if/else). Still, I wanted to point this out because in other >>> languages >>> exception-like concepts are used to convey backtracking out of >>> composite >>> control flow patterns, and if we decided to try this out for Java, >>> MatchExpression would raise its hand and say ?pick me!? -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Mon Nov 14 22:52:06 2022 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Mon, 14 Nov 2022 23:52:06 +0100 (CET) Subject: Retiring Checked Exceptions Was: Throwing Functions In-Reply-To: References: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> Message-ID: <1142617653.45463508.1668466326897.JavaMail.zimbra@u-pem.fr> > From: "John Hendrikx" > To: "Remi Forax" , "Nathan Reynolds" > > Cc: "amber-dev" , "amber-spec-experts" > , "Ron Pressler" > Sent: Saturday, November 12, 2022 5:16:10 PM > Subject: Re: Retiring Checked Exceptions Was: Throwing Functions > I very much disagree with this position, so I will make a case for checked > exceptions: > 1) Without checked exceptions, using exceptions for alternative outcomes as part > of the contract of an API would no longer be possible. This is because adding a > new exception to the API would no longer be a breaking change. Documentation is > not going to save you here. Effectively, exceptions would have only two uses > left (like in other languages): fatal JVM breaking errors and to signal > mistakes that could have been prevented by the programmer. Using them to signal > unpreventable errors would be highly suspect and likely quickly be considered a > bad practice. > In other languages (but also in some Java API's that use runtime exception to > signal unpreventable errors) the compiler cannot help you with these > alternative outcomes as it isn't even required to specify them as part of your > API. It helps you with the return value, but not for any other outcomes. These > other outcomes will now have to guessed, gleaned from the documentation (if it > is up to date), or by doing manual code mining (of the called function and all > the functions it calls). Worse, these outcomes can change in later releases > without any warning as they're non-breaking changes. I'm proposing to demote checked exceptions to make them second class citizen because this practically what they are. The problem is that the status quo is pushing people to use runtime exceptions instead of exceptions because checked exception do not compose well, exactly what we both do not want. Are you aware that Files.lines() or Files.list() are throwing UncheckedIOException ? Libraries are already hiding checked exceptions inside unchecked ones. The end game if we do nothing is that nobody will use Exception anymore because they will be hidden inside an unchecked one. I think it's far better to consider them as documentation with a warning, exacly like a a cast to a type variable or a parametrized type emit a warning that that current practice which is to hide checked exceptions inside unchecked ones. R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Mon Nov 14 22:58:29 2022 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Mon, 14 Nov 2022 23:58:29 +0100 (CET) Subject: Retiring Checked Exceptions Was: Throwing Functions In-Reply-To: References: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> Message-ID: <107377019.45464042.1668466709989.JavaMail.zimbra@u-pem.fr> > From: "Archie Cobbs" > To: "Nathan Reynolds" > Cc: "Brian Goetz" , "John Hendrikx" , > "Remi Forax" , "amber-dev" , > "amber-spec-experts" , "Ron Pressler" > > Sent: Monday, November 14, 2022 5:33:35 PM > Subject: Re: Retiring Checked Exceptions Was: Throwing Functions > On Sat, Nov 12, 2022 at 5:26 PM Nathan Reynolds < [ > mailto:numeralnathan at gmail.com | numeralnathan at gmail.com ] > wrote: >>> I've found that there are a lot of people out there who quietly think checked >> > exceptions are ... pretty OK. >> Count me in this camp. Checked exceptions are so much better than error return >> codes. > I like checked exceptions also. > But so what? Of course everyone including me is going to have some opinion... > the deeper question is, what are we trying to optimize for in a programming > language? > Well I'm sure everyone has an opinion on that question as well.. but at least > that question is a little closer to the heart of the matter. > A problem I've seen with programming language design happens in other fields as > well. Consider building architecture for example. Architects can sometimes > drift from optimizing for the humans that will occupy the space (what should be > their goal) to optimizing for simplicity, beauty, and elegance (what they > really want to be their goal). > Simplicity, beauty, and elegance are all well and good until they start > detracting from the more important goal of serving the humans. Have you ever > had dinner in a nice restaurant that has sleek & beautiful architecture, but > because of all the open space it's really drafty and because of the hard > concrete ceilings and resulting terrible acoustics you can barely understand > what anyone across the table is saying? (yes, that just happened a few weeks > ago) > So here's my opinion on what we should be optimizing for, from my own little > perspective. > I'm not a language designer (those folks are a lot smarter than me :) I'm just a > regular Java user for 20+ years. My main development responsibility right now > is an enterprise web application with ~150,000 lines of code, plus millions of > LOC incorporated by reference (Spring, Hibernate, Tomcat, Linux, etc.). > But the windows on my screen are only ~54 lines tall. > That means I can inspect at most 0.03% of the code at any one time, and yet I'm > supposed to somehow ensure this whole thing works properly without any bugs. > Therefore, to me the most important property of a programming language is this: > how hard is it to look at a chunk of code on the screen and be able to convince > myself that it will do what it's supposed to and not contribute any bugs? > Is most of the critical information there in front of me? Can I convince myself > I'm looking at a seaworthy vessel of logical correctness? > Or are there a bunch of "leaks" that I either have to patch, or (almost worse) > do a bunch of research to finally realize that in fact they really aren't leaks > after all? > How hard is it to hunt down the information that's not explicitly on the screen > that I need to feel confident in what I'm looking at? > No doubt Java would be more simple, beautiful, and elegant without checked > exceptions. But checked exceptions are explicit information on the screen > relating to what error cases can possibly occur. They appear pretty much when > and where you need to see them. And the compiler guarantees that you won't > accidentally miss one. > From the perspective of "Help me prove this code is correct and handles all the > possible error cases" what's not to love about that?? > Features that help my cause: > - Compile time explicit strong typing > - Precisely defined semantics (compare to C: order of execution, memory model, > etc.) > - Easily accessible Javadocs that specify behavior precisely > - Compiler warnings > - @Overrides > - Checked exceptions > Features that don't help my cause (they're not bad, they're just less > important): > - Anything that optimizes for the speed of writing code rather than the speed of > reading it > - Anything that optimizes for code brevity (if that were the goal, we'd all be > using perl!) > An example of the latter is the new "var" keyword. Yes it makes it faster to > WRITE code, but it makes it a tiny bit slower to READ code. It means to > understand what "foo" is, I have to do one little tiny extra step of type > inference in my head. Not a big deal, and I'm certainly not opposed to the > feature, but I probably won't use it much. > Java's "target market" as it were is large enterprise projects. Regarding such > projects, a wise person once said: You write code once, but you maintain it > forever. What if checked exceptions work like unchecked casts ? What if instead of a compiler error you still have a warning when you suppress a checked exception, so you can write code like this public void m() throws IOException { var input = ... Runnable runnable = () -> { input.read(); }; runnable.run() ; } and you get two warnings, one because you have suppressed the IOException inside the Runnable and one because you have a throws IOException with no IOException thrown inside the body of m() ? So IOException will work seamlessly with streams, methods that takes lambdas, etc. > -Archie > -- > Archie L. Cobbs R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Nov 14 23:05:44 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 14 Nov 2022 18:05:44 -0500 Subject: Late change to JEP 433 In-Reply-To: References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> Message-ID: <3b4ebb0d-0212-1a01-6ed7-1b9b5e7806c8@oracle.com> At the time, Kevin made an excellent argument that "developers have learned that ICCE means 'your class path is borked, dude, recompile'", and a novel enum value was indicative of a borked class path.? This was compelling in context, and we went this way. As we've moved on, we realize there is a bigger picture here, so I support this change. On 11/14/2022 2:14 PM, Kevin Bourrillion wrote: > Makes complete sense to me. A switch that was acceptably exhaustive > when it was compiled can still get an unhandleable value at runtime > for I think a small handful of different reasons, and with your change > they would all throw the same thing, correct? I don't fully remember > the points I made about ICCError, but surely this overrides them! > > > On Mon, Nov 14, 2022 at 4:38 AM Gavin Bierman > wrote: > > Dear Experts, > > As we put the final polish on features for JDK20, we noticed that > we have an opportunity to make a very small breaking change (as > part of the preview feature) to simplify our lives. I?m writing to > see what you think. > > tldr: A switch expression over an enum class should throw > MatchException rather than IncompatibleClassChangeError if no > switch label applies at runtime. > > Details: > > When we introduced switch expressions, we opted for a design where > the switch body had to be exhaustive. When switching over an enum > type, a switch body with case labels supporting all the enum > constants for the enum type is considered exhaustive, meaning a > default clause is not needed. > > However, there is a possibility that the enum class is changed > after compilation of the switch expression, and a new enum > constant added. Then when executing the switchexpression, no label > would apply. > > The question we faced in JDK14 was what to do at this point. We > decided on IncompatibleClassChangeError as that was a pre-existing > exception that was generally understood by developers as a signal > that things have got out of sync and re-compilation is needed. > > Back to the present day, with the support of pattern switches, we > can now write switches over a sealed type. When switching over a > sealed type, a switch body with case labels with type patterns > matching all the permitted subclasses is considered exhaustive, > meaning a default clause is not needed. > > If the sealed hierarchy has been changed after compilation of the > switch, it is possible that when executing the switch that no > label would apply. In this case we have settled on throwing a > MatchException. > > Throughout our design process, we have noticed the connection > between enum classes/enum constants and sealed class/permitted > subclasses ? they are essentially the same thing up the term/type > hierarchy. Moreover, in a future release, we plan to support case > labels with a mix of sealed class type patterns and enum constants. > > But we now have an inconsistency - one throws > IncompatibleClassChangeException in a bad situation and the other > MatchException which will make this future development almost > impossible. We need these cases to throw the same exception: > MatchException. So we propose to make the small breaking case to > the language that switch expressions over enum classes throw > MatchException should no switch label apply in the switch body. > > People who deliberately change their enum classes by adding new > constants, and do not recompile their switches over this enum > class, and rely on this throwing ICCE will notice this breaking > change. We think this is a vanishingly small set of developers. > The vast majority of developers, on the other hand, will thank us > for this unification, especially if it enables other new features > down the road. > > What do you think? > > Thanks, > Gavin > > > > -- > Kevin Bourrillion?|?Java Librarian |?Google, Inc.?|kevinb at google.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Nov 14 23:15:49 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 14 Nov 2022 18:15:49 -0500 Subject: Retiring Checked Exceptions Was: Throwing Functions In-Reply-To: <107377019.45464042.1668466709989.JavaMail.zimbra@u-pem.fr> References: <839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr> <107377019.45464042.1668466709989.JavaMail.zimbra@u-pem.fr> Message-ID: A brief reminder: this is getting out of the charter of amber-dev. On 11/14/2022 5:58 PM, forax at univ-mlv.fr wrote: > > > ------------------------------------------------------------------------ > > *From: *"Archie Cobbs" > *To: *"Nathan Reynolds" > *Cc: *"Brian Goetz" , "John Hendrikx" > , "Remi Forax" , "amber-dev" > , "amber-spec-experts" > , "Ron Pressler" > > *Sent: *Monday, November 14, 2022 5:33:35 PM > *Subject: *Re: Retiring Checked Exceptions Was: Throwing Functions > > On Sat, Nov 12, 2022 at 5:26 PM Nathan Reynolds > wrote: > > > I've found that there are a lot of people out there who > quietly think checked exceptions are ... pretty OK. > > Count me in this camp.? Checked exceptions are so much better > than error return codes. > > > I like checked exceptions also. > > But so what? Of course everyone including me is going to have some > opinion... the deeper question is, what are we trying to optimize > for in a programming language? > > Well I'm sure everyone has an opinion on that question as well.. > but at least that question is a little closer to the heart of the > matter. > > A problem I've seen with programming language design happens in > other fields as well. Consider building architecture for example. > Architects can sometimes drift from optimizing for the humans that > will occupy the space (what should be their goal) to optimizing > for simplicity, beauty, and elegance (what they really want to be > their goal). > > Simplicity, beauty, and elegance are all well and good until they > start detracting from the more important goal of serving the > humans. Have you ever had dinner in a nice restaurant that has > sleek & beautiful architecture, but because of all the open space > it's really drafty and because of the hard concrete ceilings and > resulting terrible acoustics you can barely understand what anyone > across the table is saying? (yes, that just happened a few weeks ago) > > So here's my opinion on what we should be optimizing for, from my > own little perspective. > > I'm not a language designer (those folks are a lot smarter than me > :) I'm just a regular Java user for 20+ years. My main development > responsibility right now is an enterprise web application with > ~150,000 lines of code, plus millions of LOC incorporated by > reference (Spring, Hibernate, Tomcat, Linux, etc.). > > But the windows on my screen are only ~54 lines tall. > > That means I can inspect at most 0.03% of the code at any one > time, and yet I'm supposed to somehow ensure this whole thing > works properly without any bugs. > > Therefore, to me the most important property of a programming > language is this: how hard is it to look at a chunk of code on the > screen and be able to convince myself that it will do what it's > supposed to and not contribute any bugs? > > Is most of the critical information there in front of me? Can I > convince myself I'm looking at a seaworthy vessel of logical > correctness? > > Or are there a bunch of "leaks" that I either have to patch, or > (almost worse) do a bunch of research to finally realize that in > fact they really aren't leaks after all? > > How hard is it to hunt down the information that's not explicitly > on the screen that I need to feel confident in what I'm looking at? > > No doubt Java would be more simple, beautiful, and elegant without > checked exceptions. But checked exceptions are explicit > information on the screen relating to what error cases can > possibly occur. They appear pretty much when and where you need to > see them. And the compiler guarantees that you won't accidentally > miss one. > > From the perspective of "Help me prove this code is correct and > handles all the possible error cases" what's not to love about that?? > > Features that help my cause: > ? - Compile time explicit strong typing > ? - Precisely defined semantics (compare to C: order of execution, > memory model, etc.) > ? - Easily accessible Javadocs that specify behavior precisely > ? - Compiler warnings > ? - @Overrides > ? - Checked exceptions > > Features that don't help my cause (they're not bad, they're just > less important): > ? - Anything that optimizes for the speed of writing code rather > than the speed of reading it > ? - Anything that optimizes for code brevity (if that were the > goal, we'd all be using perl!) > > An example of the latter is the new "var" keyword. Yes it makes it > faster to WRITE code, but it makes it a tiny bit slower to READ > code. It means to understand what "foo" is, I have to do one > little tiny extra step of type inference in my head. Not a big > deal, and I'm certainly not opposed to the feature, but I probably > won't use it much. > > Java's "target market" as it were is large enterprise projects. > Regarding such projects, a wise person once said: /You write code > once, but you maintain it forever./ > > > What if checked exceptions work like unchecked casts ? > > What if instead of a compiler error you still have a warning when you > suppress a checked exception, so you can write code like this > > ? public void m() throws IOException { > ??? var input = ... > ??? Runnable runnable = () -> { > ?????? input.read(); > ??? }; > ??? runnable.run() > ;? } > > and you get two warnings, one because you have suppressed the > IOException inside the Runnable and one because you have a throws > IOException with no IOException thrown inside the body of m() ? > > So IOException will work seamlessly with streams, methods that takes > lambdas, etc. > > > > -Archie > > -- > Archie L. Cobbs > > > R?mi > -------------- next part -------------- An HTML attachment was scrubbed... URL: From angelos.bimpoudis at oracle.com Mon Nov 14 23:20:51 2022 From: angelos.bimpoudis at oracle.com (Angelos Bimpoudis) Date: Mon, 14 Nov 2022 23:20:51 +0000 Subject: Support for primitive types in instanceof and type patterns Message-ID: Dear experts, The draft JEP for adding support for primitive types in instanceof? and type patterns, that has been previously discussed on this list, is available at: https://bugs.openjdk.org/browse/JDK-8288476 Suggestions are welcomed! Angelos -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Mon Nov 14 23:23:53 2022 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 15 Nov 2022 00:23:53 +0100 (CET) Subject: Late change to JEP 433 In-Reply-To: <94e5524b-ffde-7af0-e7c8-f7d659fc1a89@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> <842334026.45461578.1668465117769.JavaMail.zimbra@u-pem.fr> <94e5524b-ffde-7af0-e7c8-f7d659fc1a89@oracle.com> Message-ID: <1523992166.45467714.1668468233208.JavaMail.zimbra@u-pem.fr> > From: "Brian Goetz" > To: "Remi Forax" , "John Rose" > Cc: "Alex Buckley" , "amber-spec-experts" > > Sent: Monday, November 14, 2022 11:40:27 PM > Subject: Re: Late change to JEP 433 > Its MatchException. Error would not be appropriate, since this is the same > exception that gets used for remainder (e.g., Box(Box(var x)) against a target > of Box(null)). I still think we should throw a NPE when a destructuring something which is null. It will make the semantics of MatchException very similar to LambdaConversionException, i.e. a lot of users will never see it because it can be thrown only when there is a separate compilation issue or a bug in the deconstructor. If you take a look to the implementation, the NPEs can be thrown organically as the result of calling the deconstructor (or the accessor methods) on null, instead of adding a nullcheck that goto to the location where the MatchException is thrown. R?mi > On 11/14/2022 5:31 PM, Remi Forax wrote: >> I'm confused, is it MatchError or MatchException ? >> Because if it's an error instead of an exception, it may be less an issue in >> term of backward compatibility but it is not what is proposed, right ? >> R?mi >> ----- Original Message ----- >>> From: "John Rose" [ mailto:john.r.rose at oracle.com | ] >>> To: "Alex Buckley" [ mailto:alex.buckley at oracle.com | >>> ] Cc: "amber-spec-experts" [ mailto:amber-spec-experts at openjdk.java.net | >>> ] Sent: Monday, November 14, 2022 8:24:04 >>> PM >>> Subject: Re: Late change to JEP 433 >>> On 14 Nov 2022, at 10:56, Alex Buckley wrote: >>>> ? ICCE can hand over to MatchException ? >>> Precisely; I agree that it is time for this to happen. Thanks, Alex for >>> reminding us of the history and lineage of ICCE, and why it doesn?t make sense >>> for switch statements (not even classic switch-over-enum). >>> As a program linkage error, ICCE is necessarily uncommunicative when applied to >>> a misconfigured switch statement. Using a MatchError is on the other hand >>> highly informative: The user (and possibly try/catch logic surrounding the >>> failure) knows exactly what happened, that a set of matches expected to succeed >>> has failed. >>> So, here?s a possible knock-on advantage if we hand off from ICCE to ME: If >>> there is further development of the concept of ?a set of matches which is >>> required to succeed?, the error processing can continue to be unified under the >>> ME. Brian?s ideas about ?let-statements? entail a single pattern which is >>> required to match; ME is surely the right way to signal failure (if not >>> something more specific like CCE or NPE, which is an interesting >>> side-conversation). Or, if we ever did Haskell-style method overloads that >>> discriminate arguments by means of patterns, surely they would desugar to >>> omnibus methods that start with switches; once again ME surely makes sense as a >>> way to signal inapplicability of such match-based methods. >>> ? John >>> P.S. More speculatively, and probably a bridge too far, would be to employ >>> MatchException as a part of a meta-language protocol that defines how sets of >>> patterns compose, and in particular how one part of a composite signals failure >>> to the whole composite. (Surely there is some future use for X in methods : >>> method handles :: patterns : X; that?s what I mean by a meta-language >>> protocol.) I say this is a bridge too far because Java exceptions are not a >>> very good tool for normally-frequent control flow, and also because ME, like >>> NPE or CCE, probably best signals a failure of the programmer?s settled >>> intentions about some code, rather than signaling an alternative control path >>> (like if/else). Still, I wanted to point this out because in other languages >>> exception-like concepts are used to convey backtracking out of composite >>> control flow patterns, and if we decided to try this out for Java, >>> MatchExpression would raise its hand and say ?pick me!? -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Nov 14 23:35:24 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 14 Nov 2022 18:35:24 -0500 Subject: Late change to JEP 433 In-Reply-To: <1523992166.45467714.1668468233208.JavaMail.zimbra@u-pem.fr> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> <842334026.45461578.1668465117769.JavaMail.zimbra@u-pem.fr> <94e5524b-ffde-7af0-e7c8-f7d659fc1a89@oracle.com> <1523992166.45467714.1668468233208.JavaMail.zimbra@u-pem.fr> Message-ID: <50b26a1d-b797-15f6-19e0-c7e2bb0bd04f@oracle.com> I win my bet!? I had my money on "If you send this, Remi will surely attempt to reopen his pet NPE issue."? We have been through this all before, so unless you have something dramatically new and compelling, we're not reopening this issue now. As a reminder, not all causes of MatchException come from separate compilation anomalies.? Some come from match remainder, which is just an ordinary domain error, and separating the two is only possible in the easy cases. I am not sure you fully understand how this works, otherwise you wouldn't keep raising the same issue after getting the same explanation.? (For example, the "NPE can be thrown organically" claim you make here, which you've made before, is wrong; it is possible a later pattern can match Box(null), and we do not throw ME until all choices are exhausted.) On 11/14/2022 6:23 PM, forax at univ-mlv.fr wrote: > > > ------------------------------------------------------------------------ > > *From: *"Brian Goetz" > *To: *"Remi Forax" , "John Rose" > > *Cc: *"Alex Buckley" , > "amber-spec-experts" > *Sent: *Monday, November 14, 2022 11:40:27 PM > *Subject: *Re: Late change to JEP 433 > > Its MatchException.? Error would not be appropriate, since this is > the same exception that gets used for remainder (e.g., Box(Box(var > x)) against a target of Box(null)). > > > I still think we should throw a NPE when a destructuring something > which is null. > > It will make the semantics of MatchException very similar to > LambdaConversionException, i.e. a lot of users will never see it > because it can be thrown only when there is a separate compilation > issue or a bug in the deconstructor. > > If you take a look to the implementation, the NPEs can be thrown > organically as the result of calling the deconstructor (or the > accessor methods) on null, instead of adding a nullcheck that goto to > the location where the MatchException is thrown. > > R?mi > > > > On 11/14/2022 5:31 PM, Remi Forax wrote: > > I'm confused, is it MatchError or MatchException ? > > Because if it's an error instead of an exception, it may be less an issue in term of backward compatibility but it is not what is proposed, right ? > > R?mi > > ----- Original Message ----- > > From: "John Rose" > To: "Alex Buckley" > Cc: "amber-spec-experts" > Sent: Monday, November 14, 2022 8:24:04 PM > Subject: Re: Late change to JEP 433 > > On 14 Nov 2022, at 10:56, Alex Buckley wrote: > > ? ICCE can hand over to MatchException ? > > Precisely; I agree that it is time for this to happen. Thanks, Alex for > reminding us of the history and lineage of ICCE, and why it doesn?t make sense > for switch statements (not even classic switch-over-enum). > > As a program linkage error, ICCE is necessarily uncommunicative when applied to > a misconfigured switch statement. Using a MatchError is on the other hand > highly informative: The user (and possibly try/catch logic surrounding the > failure) knows exactly what happened, that a set of matches expected to succeed > has failed. > > So, here?s a possible knock-on advantage if we hand off from ICCE to ME: If > there is further development of the concept of ?a set of matches which is > required to succeed?, the error processing can continue to be unified under the > ME. Brian?s ideas about ?let-statements? entail a single pattern which is > required to match; ME is surely the right way to signal failure (if not > something more specific like CCE or NPE, which is an interesting > side-conversation). Or, if we ever did Haskell-style method overloads that > discriminate arguments by means of patterns, surely they would desugar to > omnibus methods that start with switches; once again ME surely makes sense as a > way to signal inapplicability of such match-based methods. > > ? John > > P.S. More speculatively, and probably a bridge too far, would be to employ > MatchException as a part of a meta-language protocol that defines how sets of > patterns compose, and in particular how one part of a composite signals failure > to the whole composite. (Surely there is some future use for X in methods : > method handles :: patterns : X; that?s what I mean by a meta-language > protocol.) I say this is a bridge too far because Java exceptions are not a > very good tool for normally-frequent control flow, and also because ME, like > NPE or CCE, probably best signals a failure of the programmer?s settled > intentions about some code, rather than signaling an alternative control path > (like if/else). Still, I wanted to point this out because in other languages > exception-like concepts are used to convey backtracking out of composite > control flow patterns, and if we decided to try this out for Java, > MatchExpression would raise its hand and say ?pick me!? > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From alex.buckley at oracle.com Tue Nov 15 00:23:51 2022 From: alex.buckley at oracle.com (Alex Buckley) Date: Mon, 14 Nov 2022 16:23:51 -0800 Subject: Late change to JEP 433 In-Reply-To: <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> Message-ID: On 11/14/2022 10:56 AM, Alex Buckley wrote: > (I think JLS 11.1.2 "The Causes of Exceptions" ought to mention an > `assert` statement -- filed https://bugs.openjdk.org/browse/JDK-8296951) In the spirit of fixing omissions, a list member told me that JLS 15.27.4 omits to mention that a LambdaConversionException can occur. This exception arises from the operation of LambdaMetaFactory, which is a mechanism provided by the Java Platform for implementing 15.27.4 (see the javadoc of j.l.i.LambdaMetafactory::metafactory). However, per https://bugs.openjdk.org/browse/JDK-8059640, any LambdaConversionException will surface as a LinkageError, and the precise timing of a LinkageError is specified as unspecified by JLS 15.6: "Various linkage and virtual machine errors may also occur during the evaluation of an expression. By their nature, such errors are difficult to predict and difficult to handle." Given that use of LambdaMetaFactory is optional (note "a mechanism", not "the mechanism"), and given that LambdaConversionException is not visible even when it is used, I don't see any need to change 15.27.4. Alex From forax at univ-mlv.fr Tue Nov 15 07:20:22 2022 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 15 Nov 2022 08:20:22 +0100 (CET) Subject: Late change to JEP 433 In-Reply-To: <50b26a1d-b797-15f6-19e0-c7e2bb0bd04f@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> <842334026.45461578.1668465117769.JavaMail.zimbra@u-pem.fr> <94e5524b-ffde-7af0-e7c8-f7d659fc1a89@oracle.com> <1523992166.45467714.1668468233208.JavaMail.zimbra@u-pem.fr> <50b26a1d-b797-15f6-19e0-c7e2bb0bd04f@oracle.com> Message-ID: <533996683.45644378.1668496822939.JavaMail.zimbra@u-pem.fr> > From: "Brian Goetz" > To: "Remi Forax" > Cc: "John Rose" , "Alex Buckley" > , "amber-spec-experts" > > Sent: Tuesday, November 15, 2022 12:35:24 AM > Subject: Re: Late change to JEP 433 > I win my bet! I had my money on "If you send this, Remi will surely attempt to > reopen his pet NPE issue." We have been through this all before, so unless you > have something dramatically new and compelling, we're not reopening this issue > now. > As a reminder, not all causes of MatchException come from separate compilation > anomalies. Some come from match remainder, which is just an ordinary domain > error, and separating the two is only possible in the easy cases. > I am not sure you fully understand how this works, otherwise you wouldn't keep > raising the same issue after getting the same explanation. (For example, the > "NPE can be thrown organically" claim you make here, which you've made before, > is wrong; it is possible a later pattern can match Box(null), and we do not > throw ME until all choices are exhausted.) Let say we have, record Box(Box b) { } and Box box = ... switch(box) { case Box(Box(var value)) -> ... // 1 case Box value2 -> ... // 2 } you can translate it line by line that way, if (box == null) { throw new NPE(); } if (box instanceof Box $b1) { Box $b2 = $b1.b; if ($b2 instanceof Box value) { ... // 1 } } if (box instanceof Box value2) { ... // 2 } throw new MatchException(...) but - the first null check is not really needed if later you ask for the content of the box, - the instanceofs "box instanceof Box $b1" and "box instanceof Box value2" are useless and you do not need to do that check twice a better code is Box $b2 = box.b; // will throw a NPE if ($b2 == null) { ... // 2 } Box value2 = $b2; ... // 1 You can observe that like the switch on strings or the switch on enums, the NPE comes "organically" from asking the content of the box. The "throw new MatchException" disappears because there is no need for a catch all anymore, this is also true if the last instanceof on a subtype of a sealed type is transformed to a cast instead of an instanceof. But generating such code requires to merge subsequent patterns like Jan has tried to do in a recent patch, something i believe we will have to do anyway because the current perf is not that great. R?mi > On 11/14/2022 6:23 PM, [ mailto:forax at univ-mlv.fr | forax at univ-mlv.fr ] wrote: >>> From: "Brian Goetz" [ mailto:brian.goetz at oracle.com | ] >>> To: "Remi Forax" [ mailto:forax at univ-mlv.fr | ] , "John >>> Rose" [ mailto:john.r.rose at oracle.com | ] >>> Cc: "Alex Buckley" [ mailto:alex.buckley at oracle.com | >>> ] , "amber-spec-experts" [ mailto:amber-spec-experts at openjdk.java.net | >>> ] >>> Sent: Monday, November 14, 2022 11:40:27 PM >>> Subject: Re: Late change to JEP 433 >>> Its MatchException. Error would not be appropriate, since this is the same >>> exception that gets used for remainder (e.g., Box(Box(var x)) against a target >>> of Box(null)). >> I still think we should throw a NPE when a destructuring something which is >> null. >> It will make the semantics of MatchException very similar to >> LambdaConversionException, i.e. a lot of users will never see it because it can >> be thrown only when there is a separate compilation issue or a bug in the >> deconstructor. >> If you take a look to the implementation, the NPEs can be thrown organically as >> the result of calling the deconstructor (or the accessor methods) on null, >> instead of adding a nullcheck that goto to the location where the >> MatchException is thrown. >> R?mi >>> On 11/14/2022 5:31 PM, Remi Forax wrote: >>>> I'm confused, is it MatchError or MatchException ? >>>> Because if it's an error instead of an exception, it may be less an issue in >>>> term of backward compatibility but it is not what is proposed, right ? >>>> R?mi >>>> ----- Original Message ----- >>>>> From: "John Rose" [ mailto:john.r.rose at oracle.com | ] >>>>> To: "Alex Buckley" [ mailto:alex.buckley at oracle.com | >>>>> ] Cc: "amber-spec-experts" [ mailto:amber-spec-experts at openjdk.java.net | >>>>> ] Sent: Monday, November 14, 2022 8:24:04 >>>>> PM >>>>> Subject: Re: Late change to JEP 433 >>>>> On 14 Nov 2022, at 10:56, Alex Buckley wrote: >>>>>> ? ICCE can hand over to MatchException ? >>>>> Precisely; I agree that it is time for this to happen. Thanks, Alex for >>>>> reminding us of the history and lineage of ICCE, and why it doesn?t make sense >>>>> for switch statements (not even classic switch-over-enum). >>>>> As a program linkage error, ICCE is necessarily uncommunicative when applied to >>>>> a misconfigured switch statement. Using a MatchError is on the other hand >>>>> highly informative: The user (and possibly try/catch logic surrounding the >>>>> failure) knows exactly what happened, that a set of matches expected to succeed >>>>> has failed. >>>>> So, here?s a possible knock-on advantage if we hand off from ICCE to ME: If >>>>> there is further development of the concept of ?a set of matches which is >>>>> required to succeed?, the error processing can continue to be unified under the >>>>> ME. Brian?s ideas about ?let-statements? entail a single pattern which is >>>>> required to match; ME is surely the right way to signal failure (if not >>>>> something more specific like CCE or NPE, which is an interesting >>>>> side-conversation). Or, if we ever did Haskell-style method overloads that >>>>> discriminate arguments by means of patterns, surely they would desugar to >>>>> omnibus methods that start with switches; once again ME surely makes sense as a >>>>> way to signal inapplicability of such match-based methods. >>>>> ? John >>>>> P.S. More speculatively, and probably a bridge too far, would be to employ >>>>> MatchException as a part of a meta-language protocol that defines how sets of >>>>> patterns compose, and in particular how one part of a composite signals failure >>>>> to the whole composite. (Surely there is some future use for X in methods : >>>>> method handles :: patterns : X; that?s what I mean by a meta-language >>>>> protocol.) I say this is a bridge too far because Java exceptions are not a >>>>> very good tool for normally-frequent control flow, and also because ME, like >>>>> NPE or CCE, probably best signals a failure of the programmer?s settled >>>>> intentions about some code, rather than signaling an alternative control path >>>>> (like if/else). Still, I wanted to point this out because in other languages >>>>> exception-like concepts are used to convey backtracking out of composite >>>>> control flow patterns, and if we decided to try this out for Java, >>>>> MatchExpression would raise its hand and say ?pick me!? -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Nov 15 13:44:10 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 15 Nov 2022 08:44:10 -0500 Subject: Late change to JEP 433 In-Reply-To: <533996683.45644378.1668496822939.JavaMail.zimbra@u-pem.fr> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <3f3cf1be-482e-5930-4fb8-3c7144676a15@oracle.com> <7D1CD2CD-0020-4C0C-B8BF-9619CC9E439A@oracle.com> <842334026.45461578.1668465117769.JavaMail.zimbra@u-pem.fr> <94e5524b-ffde-7af0-e7c8-f7d659fc1a89@oracle.com> <1523992166.45467714.1668468233208.JavaMail.zimbra@u-pem.fr> <50b26a1d-b797-15f6-19e0-c7e2bb0bd04f@oracle.com> <533996683.45644378.1668496822939.JavaMail.zimbra@u-pem.fr> Message-ID: <0adb4db0-cc39-953f-5608-44a6bccee00b@oracle.com> > we're not reopening this issue now. > > > Let say we have, Let's not. By continuing down this tangent, you're really doing Gavin a disservice here.? Gavin had a narrow, focused, urgent question.? By continuing this thread, he's stalled, and probably sitting on hot coals because we want to get this JEP wrapped up.? And you're reopening old issues with "but you could translate it differently" -- after being reminded that this is an already-litigated issue. This is disruptive.? I shouldn't have to ask twice. It's possible you have a point,? and I get that it is frustrating to have a point and have no one else get it, but if you want people to get it, I think you need to go about it a different way. Do you have any response to Gavin's query? -------------- next part -------------- An HTML attachment was scrubbed... URL: From heidinga at redhat.com Tue Nov 15 14:28:14 2022 From: heidinga at redhat.com (Dan Heidinga) Date: Tue, 15 Nov 2022 09:28:14 -0500 Subject: Late change to JEP 433 In-Reply-To: References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> Message-ID: Thanks Gavin for proposing this change. I'm also in agreement we should make this change now - especially given JEP 433 is still a preview feature. If we don't standardize the missing enum exception to MatchException now, then as Brian points out, we'll have a hard time making switches over enums consistent with other pattern switches. --Dan On Mon, Nov 14, 2022 at 7:39 AM Gavin Bierman wrote: > Dear Experts, > > As we put the final polish on features for JDK20, we noticed that we have > an opportunity to make a very small breaking change (as part of the preview > feature) to simplify our lives. I?m writing to see what you think. > > tldr: A switch expression over an enum class should throw MatchException > rather than IncompatibleClassChangeError if no switch label applies at > runtime. > > Details: > > When we introduced switch expressions, we opted for a design where the > switch body had to be exhaustive. When switching over an enum type, a > switch body with case labels supporting all the enum constants for the enum > type is considered exhaustive, meaning a default clause is not needed. > > However, there is a possibility that the enum class is changed after > compilation of the switch expression, and a new enum constant added. Then > when executing the switchexpression, no label would apply. > > The question we faced in JDK14 was what to do at this point. We decided on > IncompatibleClassChangeError as that was a pre-existing exception that was > generally understood by developers as a signal that things have got out of > sync and re-compilation is needed. > > Back to the present day, with the support of pattern switches, we can now > write switches over a sealed type. When switching over a sealed type, a > switch body with case labels with type patterns matching all the permitted > subclasses is considered exhaustive, meaning a default clause is not needed. > > If the sealed hierarchy has been changed after compilation of the switch, > it is possible that when executing the switch that no label would apply. In > this case we have settled on throwing a MatchException. > > Throughout our design process, we have noticed the connection between enum > classes/enum constants and sealed class/permitted subclasses ? they are > essentially the same thing up the term/type hierarchy. Moreover, in a > future release, we plan to support case labels with a mix of sealed class > type patterns and enum constants. > > But we now have an inconsistency - one throws > IncompatibleClassChangeException in a bad situation and the other > MatchException which will make this future development almost impossible. > We need these cases to throw the same exception: MatchException. So we > propose to make the small breaking case to the language that switch > expressions over enum classes throw MatchException should no switch label > apply in the switch body. > > People who deliberately change their enum classes by adding new constants, > and do not recompile their switches over this enum class, and rely on this > throwing ICCE will notice this breaking change. We think this is a > vanishingly small set of developers. The vast majority of developers, on > the other hand, will thank us for this unification, especially if it > enables other new features down the road. > > What do you think? > > Thanks, > Gavin -------------- next part -------------- An HTML attachment was scrubbed... URL: From robbepincket at live.be Tue Nov 15 17:27:25 2022 From: robbepincket at live.be (Robbe Pincket) Date: Tue, 15 Nov 2022 17:27:25 +0000 Subject: Draft Spec for Fourth Preview of Pattern Matching for Switch (JEP 433) and Second Preview of Record Patterns (JEP 432) now available In-Reply-To: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> Message-ID: Hi experts I wanted to say something about the NPE discussions that happened the last few days, but decided against it as I felt that my thoughts had already been brought up and thus my comment wouldn't really add anything new to the discussion. However while checking on some things in the current proposed spec, I did come across the following wording that felt wrong In 14.30.2 Pattern Matching: > If execution of the invocation of the accessor method completes abruptly for reason S, then pattern matching completes abruptly by throwing a MatchException with cause S. Invocations can only complete by throwing exceptions, but using the catchall "completes abruptly for reason S" feels wrong to because the reason is not the "Exception V" that has been thrown, but is "throw with value V", and I can only add "V" as a cause of an exception, not "throw with value V". A better wording might be this (based on 12.4.2 number 11 in numbered list) > If the execution of the invocation of the accessor method completes abruptly by throwing some exception E, then pattern matching completes abruptly by throwing a MatchException with cause E. Kind regards Robbe Pincket Ps. I was also wondering if could get a response to my earlier question on this list From: Gavin Bierman Sent: woensdag 19 oktober 2022 0:23 To: amber-spec-experts Subject: Draft Spec for Fourth Preview of Pattern Matching for Switch (JEP 433) and Second Preview of Record Patterns (JEP 432) now available Dear experts: The first draft of a joint spec covering JEP 433 (Fourth Preview of Pattern Matching for switch) and JEP 432 (Record Patterns) is available at: https://cr.openjdk.java.net/~gbierman/jep432+433/latest This covers all the changes for these JEPs *apart* from the proposal to infer type arguments in patterns. This will be added and announced shortly. Comments welcomed! Gavin -------------- next part -------------- An HTML attachment was scrubbed... URL: From robbepincket at live.be Tue Nov 15 19:42:50 2022 From: robbepincket at live.be (Robbe Pincket) Date: Tue, 15 Nov 2022 19:42:50 +0000 Subject: Draft Spec for Fourth Preview of Pattern Matching for Switch (JEP 433) and Second Preview of Record Patterns (JEP 432) now available In-Reply-To: <586AADA9-E4B6-4656-A68E-5436BC188A2B@oracle.com> References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> <586AADA9-E4B6-4656-A68E-5436BC188A2B@oracle.com> Message-ID: > 14.11.1: I'm not sure the prohibition of 'when false' makes sense. We don't complain about unreachable code in 'if (false) { ... }', for example, or consider variables touched inside the 'if' to be DU. > A possible use case is to turn a rule on or off based on a constant somewhere, or just by directly editing the code during a debugging session. This might be a response to my email: https://mail.openjdk.org/pipermail/amber-spec-comments/2022-June/000047.html In that email I mentioned that the for constant boolean expression in the guards, they were opting for the `while(true)` behaviour for `true`, but for the `if(false)` behaviour for the false case, which felt odd to me. It seems they opted for making the `false` act more like `while(false)` by making it an explicit compile error. Note however that `while(false)` produces a compile error due to the fact the it makes the body unreachable. I personally expected the decision to go the other way, I personally don't really see the usecase for having a `when true` if it isn't for enabling or disabling cases based on a static final boolean, but by making it dominate other cases, that might make it much harder to make sure the switch compiles in both cases. Is there a usecase I'm not seeing? Kind regards Robbe Pincket From: Dan Smith Sent: vrijdag 28 oktober 2022 2:52 To: Gavin Bierman Cc: amber-spec-experts Subject: Re: Draft Spec for Fourth Preview of Pattern Matching for Switch (JEP 433) and Second Preview of Record Patterns (JEP 432) now available I've reviewed the draft and put together a few patches, but here are a few more stray bits of feedback from me, most of which get into concepts and design: --- 5.5: There's this "downcast compatible" notion that was apparently introduced with instanceof pattern matching. It means a cast is legal and not unchecked. Ok. But?not all legal casts are downcasts, right? It's pretty confusing to use a term that suggests that they are. jshell> Serializable ser = "abc" ser ==> "abc" jshell> if (ser instanceof Comparable c) { System.out.println("matches");} matches --- 6.3.3.1: Maybe someday we'll have expressions nested in patterns, but for now isn't it meaningless to ask whether a pattern variable is in scope within another part of the same pattern? --- 13.4.2: I don't know if I'd talk about "migration compatibility" here. It's a rather common thing for a separately-compiled change to cause a runtime error that is not a linkage error. But previously the phrase "migration compatible" doesn't get mentioned in Chapter 13, and we don't go out of our way to label these conditions. It's just... a runtime exception. --- 14.11.1: I'm not sure the prohibition of 'when false' makes sense. We don't complain about unreachable code in 'if (false) { ... }', for example, or consider variables touched inside the 'if' to be DU. A possible use case is to turn a rule on or off based on a constant somewhere, or just by directly editing the code during a debugging session. --- 14.11.1: The compatibility rules are specified as "for all" rules, which means you can do some surprising things when they're vacuously true... double d = 23.0; switch (d) { default -> System.out.println("ok"); } // no error (This is an "enhanced switch", so requires a default to be exhaustive.) This seems okay to me?Java doesn't prevent all stupid programs?but worth a sanity check. And we should be careful not to make assertions that claim such switches can't be written. --- 14.11.1: A couple of dominance design notes: - Claiming that a guarded type pattern dominates a constant seems overly-nannying to me. Usually, these sorts of errors occur because the compiler can *prove* you've done something stupid (e.g., "this cast will always fail"). Here, the compiler is assuming the switch rule is stupid unless the programmer can prove it's not, to the compiler's satisfaction. And the compiler isn't very smart! Suggestion: just leave guarded type patterns out, they don't dominate anything else. - It's weird that 'null' is the one case constant that can't come after a 'default', given that 'null' is the one value that can't be handled by a 'default'. :-) Since we have to allow other case constants after 'default' anyway, I think it's best to allow 'null' as one more. ("default dominates everything except constants" is a rule I can remember.) (Also note?and I think this is good?that the dominance rules for 'default' don't care whether this is an "enhanced switch" or not. The fewer things that depend on enhanced vs. traditional, the better.) --- 14.11.1: I don't think we prevent this scenario: switch (obj) { case String s: case Object o: } The rules about duplicate pattern labels apply to "a statement is labeled...". There's no labeled statement here. I think we should probably prohibit this, for the same code hygiene reason that we prohibit it before a statement group that doesn't try to use any of the variables. (This would not be a legal switch expression, because switch expressions can't fall out. But enhanced switch statements can, as long as they're exhaustive.) --- 14.11.2: Design suggestion: rename "enhanced switch" to "pattern switch", define it as only those switches that make use of patterns, and don't worry about the remaining "switch with new features" corner cases. It's just such an important concept that I think there's a benefit to making the distinction really clean and obvious. E.g., asking someone new to Java to memorize the ad hoc set of types that don't demand exhaustiveness seems unhelpfully complicated. (Corner cases I'm thinking about: want to use a null constant but not be exhaustive? Fine. Want to have an Object input type but an empty switch body? Pointless, but fine. Etc.) --- 14.11.3, 15.28.2: Opinionated take: we're continuing to throw ICCE when an unmatched enum constant slips through a switch, because it would be a (behaviorally) incompatible change to throw something else. Meanwhile, unmatched sealed classes get a MatchException. I think there are a tiny number of people who would notice if we changed from ICCE to MatchException for enums too, and a lot more people who will have to cope with the historical baggage going forward if we don't. We should just standardize on MatchException. Further complication: as written, a sealed-interface switch that doesn't mention any enum constants will still throw if the value that gets through happens to be an enum constant. switch (sealedThing) { case Foo f -> {} case Bar b -> {} // an enum class gets added as a permitted subclass: ICCE // a regular class gets added as a permitted subclass: ME } We could specify this differently, but I'm not sure there's a bright line that will be intuitive. --- 14.14.2: I'm sure there's been some discussion about this already, but the use of MatchException for nulls in 'for' loops but NPE for nulls in switches also seems like a sad historical wart. What's wrong with an NPE from a 'for' loop? --- 14.30.1: Parenthesized patterns are no fun for a spec writer. :-) Are they actually useful? I'm not sure I've seen an example demonstrating what they're for. (The JEP only talks about them abstractly.) Followup: would it make sense for a 'for' loop to permit a parenthesized pattern? --- 14.30.1, 14.30.2: I'm not sold on *any patterns*, *resolved patterns*, and *executable switch blocks*. The semantics are fine?some type patterns will match null, others will not. But it seems to me that this can be a property of the type pattern, one of many properties of programs that we determine at compile time. No need to frame it as rewriting a program into something else. (Compare the handling of the '+' operator. We don't rewrite to a non-denotable "concatenation expression".) Concretely: - The pattern matching runtime rules can just say "the null reference matches a type pattern if the type pattern is unconditional". - We can make it a little more clear that a type pattern is determined to be unconditional, or not, based on its context-dependent match type (is that what we call it?) For a *compiler*, it will be useful to come up with an encoding that preserves the compile-time "unconditional" property in bytecode. But that's a compiler problem, not something JLS needs to comment on. --- 14.30.3: To my ear (maybe this is an American thing?), "applicable at" sounds wrong, and it would read more naturally to say "applicable for" or "applicable to". Same for "unconditional at". --- 14.30.3: A record pattern can't match null, but for the purpose of dominance, it's not clear to me why a record pattern can't be considered unconditional, and thus dominate the equivalent type pattern or a 'default'. switch (point) { case Point(int x, int y) -> {} case Point p -> {} // unreachable default -> {} // unreachable } -------------- next part -------------- An HTML attachment was scrubbed... URL: From heidinga at redhat.com Tue Nov 15 19:55:00 2022 From: heidinga at redhat.com (Dan Heidinga) Date: Tue, 15 Nov 2022 14:55:00 -0500 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: References: Message-ID: Hi Angelos, The overall direction and writeup for this looks good to me. I think we need to be more specific about how doubles & floats fit into this though as they are perpetual source of special cases. The JEP says: > Once instanceof becomes meaningful for primitive types, this provides an obvious interpretation > for primitive type patterns (and reference type patterns as applied to a primitive target): > "could I cast the match target to the type in this pattern without error or loss of precision?" This makes sense for most of the primitives we like to think about (int, byte, char, short, long) but may be more complicated for doubles and floats. Conversions to & from float/double are hard to validate that there will be no loss of precision. if we require exact conversions for them, we'll find that they can only be applied in very narrow cases. Is that the intention or do we need a more flexible notion of "without error or loss of precision" doubles and floats? For example, "JLS 5.1.2 Widening Primitive Conversion" which is one of the valid conversions in a casting context indicates that: "A widening primitive conversion from int to float, or from long to float, or from long to double, may result in loss of precision, that is, the result may lose some of the least significant bits of the value." It would be good to expand on what the expected behaviour for floats / doubles when used with instanceof. This shouldn't take away from the overall direction of the JEP which I think is the right approach - it's just a corner case we need to clarify. --Dan On Mon, Nov 14, 2022 at 6:21 PM Angelos Bimpoudis < angelos.bimpoudis at oracle.com> wrote: > Dear experts, > > The draft JEP for adding support for primitive types in instanceof? and > type patterns, that has been previously discussed on this list, is > available at: > > https://bugs.openjdk.org/browse/JDK-8288476 > > Suggestions are welcomed! > Angelos > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Nov 15 20:13:32 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 15 Nov 2022 15:13:32 -0500 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: References: Message-ID: <7b362ea0-f93d-3cd6-d13f-568b17f6c852@oracle.com> On 11/15/2022 2:55 PM, Dan Heidinga wrote: > Hi Angelos, > > The overall direction and writeup for this looks good to me.? I think > we need to be more specific about how doubles & floats fit into this > though as they are perpetual source of special cases. Indeed, floating point is the gift that keeps on giving. Joe recently did some nice work in the spec of Float and Double, outlining the various different ways in which floats can be compared.? This allows language features like pattern matching, casting, and switch to appeal to "compared by FooBar comparison", rather than spelling it out for each use. From robbepincket at live.be Tue Nov 15 21:11:47 2022 From: robbepincket at live.be (Robbe Pincket) Date: Tue, 15 Nov 2022 21:11:47 +0000 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: References: Message-ID: Hi I did a quick look over this new jep and had some questions. 1. I was wondering if the following is legal: ```java Number num = ...; if (num instanceof byte b) { ... } ``` and if yes, is it equivalent to: ```java if (num instanceof Byte $b) { byte b = $b; ... } ``` or: ```java if ( num instanceof Long $l && $l.longValue() instanceof byte b || num instanceof Integer $i && $i.intValue() instanceof byte b || num instanceof Short $s && $s.shortValue() instanceof byte b || num instanceof Byte $b && $b.byteValue() instanceof byte b || num instanceof Character $c && $c.charValue() instanceof byte b || num instanceof Float $f && $f.floatValue() instanceof byte b || num instanceof Double $d && $d.doubleValue() instanceof byte b ) { ... } ``` To me it feels like it should be the second to match with the rest of the idea of primitive matching, but that means a rather small expression hides a lot of complexity 2. How will this interact with valhalla Currently, if I have a `record Box(T item) {}`, then item is always a reference type. However, as I understand the current plans of valhalla, this won't always be true in the future, and item could be an `int` or a `byte`. How would `intanceof Box(byte x)` end up getting compiled? I suppose that is also a question about how pattern matching interacts with universal/specialized generics in the first place, but it seems to me that this jep could influence that so it should probably be taken into consideration. Kind regards Robbe Pincket From: Angelos Bimpoudis Sent: dinsdag 15 november 2022 0:21 To: amber-spec-experts Subject: Support for primitive types in instanceof and type patterns Dear experts, The draft JEP for adding support for primitive types in instanceof? and type patterns, that has been previously discussed on this list, is available at: https://bugs.openjdk.org/browse/JDK-8288476 Suggestions are welcomed! Angelos -------------- next part -------------- An HTML attachment was scrubbed... URL: From joe.darcy at oracle.com Tue Nov 15 22:40:02 2022 From: joe.darcy at oracle.com (Joseph D. Darcy) Date: Tue, 15 Nov 2022 14:40:02 -0800 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: <7b362ea0-f93d-3cd6-d13f-568b17f6c852@oracle.com> References: <7b362ea0-f93d-3cd6-d13f-568b17f6c852@oracle.com> Message-ID: On 11/15/2022 12:13 PM, Brian Goetz wrote: > > > On 11/15/2022 2:55 PM, Dan Heidinga wrote: >> Hi Angelos, >> >> The overall direction and writeup for this looks good to me.? I think >> we need to be more specific about how doubles & floats fit into this >> though as they are perpetual source of special cases. > > Indeed, floating point is the gift that keeps on giving. > > Joe recently did some nice work in the spec of Float and Double, > outlining the various different ways in which floats can be compared.? > This allows language features like pattern matching, casting, and > switch to appeal to "compared by FooBar comparison", rather than > spelling it out for each use. > > FYI, the new text in question is: https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html#fpNumericalEq For the cases in the draft JEP, there have been separate discussions working through the details. Putting aside how it might be implemented, for the ?? floating-point type -> integral type cases, conceptually if the same real number can be presented in the floating-point type and the integral type, then the conversion is exact. (While floating-point values are often thought of as "fuzzy," each finite floating-point value represents some particular real number. Finite binary floating-point values are sums of the powers of 2 where the exponent difference of the powers is bounded by the significand width of the floating-point format in question.) The main special case is how conversion of -0.0 to an integral type is defined for purposes of instanceof. The desired double -> float behavior can be inferred from IEEE 754 concepts. HTH, -Joe From joe.darcy at oracle.com Tue Nov 15 22:40:02 2022 From: joe.darcy at oracle.com (Joseph D. Darcy) Date: Tue, 15 Nov 2022 14:40:02 -0800 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: <7b362ea0-f93d-3cd6-d13f-568b17f6c852@oracle.com> References: <7b362ea0-f93d-3cd6-d13f-568b17f6c852@oracle.com> Message-ID: On 11/15/2022 12:13 PM, Brian Goetz wrote: > > > On 11/15/2022 2:55 PM, Dan Heidinga wrote: >> Hi Angelos, >> >> The overall direction and writeup for this looks good to me.? I think >> we need to be more specific about how doubles & floats fit into this >> though as they are perpetual source of special cases. > > Indeed, floating point is the gift that keeps on giving. > > Joe recently did some nice work in the spec of Float and Double, > outlining the various different ways in which floats can be compared.? > This allows language features like pattern matching, casting, and > switch to appeal to "compared by FooBar comparison", rather than > spelling it out for each use. > > FYI, the new text in question is: https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html#fpNumericalEq For the cases in the draft JEP, there have been separate discussions working through the details. Putting aside how it might be implemented, for the ?? floating-point type -> integral type cases, conceptually if the same real number can be presented in the floating-point type and the integral type, then the conversion is exact. (While floating-point values are often thought of as "fuzzy," each finite floating-point value represents some particular real number. Finite binary floating-point values are sums of the powers of 2 where the exponent difference of the powers is bounded by the significand width of the floating-point format in question.) The main special case is how conversion of -0.0 to an integral type is defined for purposes of instanceof. The desired double -> float behavior can be inferred from IEEE 754 concepts. HTH, -Joe From gavin.bierman at oracle.com Wed Nov 16 14:57:53 2022 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Wed, 16 Nov 2022 14:57:53 +0000 Subject: Late change to JEP 433 In-Reply-To: References: <3E794F9B-EDB3-4CE3-B43E-29AA709FF8BF@oracle.com> Message-ID: <59334049-8E98-4851-B992-FDD04B46784A@oracle.com> Thanks for the replies. I have updated the spec to reflect this change: https://cr.openjdk.java.net/~gbierman/jep432+433/latest Thanks, Gavin On 14 Nov 2022, at 12:38, Gavin Bierman > wrote: Dear Experts, As we put the final polish on features for JDK20, we noticed that we have an opportunity to make a very small breaking change (as part of the preview feature) to simplify our lives. I?m writing to see what you think. tldr: A switch expression over an enum class should throw MatchException rather than IncompatibleClassChangeError if no switch label applies at runtime. Details: When we introduced switch expressions, we opted for a design where the switch body had to be exhaustive. When switching over an enum type, a switch body with case labels supporting all the enum constants for the enum type is considered exhaustive, meaning a default clause is not needed. However, there is a possibility that the enum class is changed after compilation of the switch expression, and a new enum constant added. Then when executing the switchexpression, no label would apply. The question we faced in JDK14 was what to do at this point. We decided on IncompatibleClassChangeError as that was a pre-existing exception that was generally understood by developers as a signal that things have got out of sync and re-compilation is needed. Back to the present day, with the support of pattern switches, we can now write switches over a sealed type. When switching over a sealed type, a switch body with case labels with type patterns matching all the permitted subclasses is considered exhaustive, meaning a default clause is not needed. If the sealed hierarchy has been changed after compilation of the switch, it is possible that when executing the switch that no label would apply. In this case we have settled on throwing a MatchException. Throughout our design process, we have noticed the connection between enum classes/enum constants and sealed class/permitted subclasses ? they are essentially the same thing up the term/type hierarchy. Moreover, in a future release, we plan to support case labels with a mix of sealed class type patterns and enum constants. But we now have an inconsistency - one throws IncompatibleClassChangeException in a bad situation and the other MatchException which will make this future development almost impossible. We need these cases to throw the same exception: MatchException. So we propose to make the small breaking case to the language that switch expressions over enum classes throw MatchException should no switch label apply in the switch body. People who deliberately change their enum classes by adding new constants, and do not recompile their switches over this enum class, and rely on this throwing ICCE will notice this breaking change. We think this is a vanishingly small set of developers. The vast majority of developers, on the other hand, will thank us for this unification, especially if it enables other new features down the road. What do you think? Thanks, Gavin -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Wed Nov 16 15:02:12 2022 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Wed, 16 Nov 2022 15:02:12 +0000 Subject: Updated spec for String Templates (JEP 430) now available Message-ID: <454AD280-6F7E-4AB1-AB98-6AF677EE484E@oracle.com> Dear experts: An updated spec covering JEP 430 (String Templates) is now available at: https://cr.openjdk.java.net/~gbierman/jep430/latest Comments welcomed! Gavin -------------- next part -------------- An HTML attachment was scrubbed... URL: From heidinga at redhat.com Wed Nov 16 15:15:04 2022 From: heidinga at redhat.com (Dan Heidinga) Date: Wed, 16 Nov 2022 10:15:04 -0500 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: References: <7b362ea0-f93d-3cd6-d13f-568b17f6c852@oracle.com> Message-ID: It's good to hear that you and others are thinking through the details on how float/doubles will work. I still have some concern with user-intuition when writing pattern matching code over floating point values if users base their intuition on their experience with widening casts to float. There's a great sample program (JLS Example 5.1.2-1) which shows the loss of precision when casting a large int to a float which I would try to express with pattern matching roughly as: record FloatBox(float f) {} int big = 1234567890; FloatBox box = new FloatBox(big); if (box instanceof FloatBox(int i)) { // pattern won't match here } I think users would be surprised reading the code that the pattern doesn't match because converting back to an int would lose precession. The equivalent non-pattern code would be pretty clear that it accepted the loss of precession: if (box instanceof FLoatBox) { int i = (int)box.f(); .... } Users will find it confusing when the pattern seems to match "sometimes" though this is likely due to existing confusion related to floating types. Maybe expanding on the expected implementation will make it easier to build a mental model for when the match will succeed? --Dan On Tue, Nov 15, 2022 at 6:13 PM Joseph D. Darcy wrote: > On 11/15/2022 12:13 PM, Brian Goetz wrote: > > > > > > On 11/15/2022 2:55 PM, Dan Heidinga wrote: > >> Hi Angelos, > >> > >> The overall direction and writeup for this looks good to me. I think > >> we need to be more specific about how doubles & floats fit into this > >> though as they are perpetual source of special cases. > > > > Indeed, floating point is the gift that keeps on giving. > > > > Joe recently did some nice work in the spec of Float and Double, > > outlining the various different ways in which floats can be compared. > > This allows language features like pattern matching, casting, and > > switch to appeal to "compared by FooBar comparison", rather than > > spelling it out for each use. > > > > > FYI, the new text in question is: > > > https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html#fpNumericalEq > > For the cases in the draft JEP, there have been separate discussions > working through the details. Putting aside how it might be implemented, > for the > > floating-point type -> integral type > > cases, conceptually if the same real number can be presented in the > floating-point type and the integral type, then the conversion is exact. > (While floating-point values are often thought of as "fuzzy," each > finite floating-point value represents some particular real number. > Finite binary floating-point values are sums of the powers of 2 where > the exponent difference of the powers is bounded by the significand > width of the floating-point format in question.) The main special case > is how conversion of -0.0 to an integral type is defined for purposes of > instanceof. The desired double -> float behavior can be inferred from > IEEE 754 concepts. > > HTH, > > -Joe > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From heidinga at redhat.com Wed Nov 16 15:15:04 2022 From: heidinga at redhat.com (Dan Heidinga) Date: Wed, 16 Nov 2022 10:15:04 -0500 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: References: <7b362ea0-f93d-3cd6-d13f-568b17f6c852@oracle.com> Message-ID: It's good to hear that you and others are thinking through the details on how float/doubles will work. I still have some concern with user-intuition when writing pattern matching code over floating point values if users base their intuition on their experience with widening casts to float. There's a great sample program (JLS Example 5.1.2-1) which shows the loss of precision when casting a large int to a float which I would try to express with pattern matching roughly as: record FloatBox(float f) {} int big = 1234567890; FloatBox box = new FloatBox(big); if (box instanceof FloatBox(int i)) { // pattern won't match here } I think users would be surprised reading the code that the pattern doesn't match because converting back to an int would lose precession. The equivalent non-pattern code would be pretty clear that it accepted the loss of precession: if (box instanceof FLoatBox) { int i = (int)box.f(); .... } Users will find it confusing when the pattern seems to match "sometimes" though this is likely due to existing confusion related to floating types. Maybe expanding on the expected implementation will make it easier to build a mental model for when the match will succeed? --Dan On Tue, Nov 15, 2022 at 6:13 PM Joseph D. Darcy wrote: > On 11/15/2022 12:13 PM, Brian Goetz wrote: > > > > > > On 11/15/2022 2:55 PM, Dan Heidinga wrote: > >> Hi Angelos, > >> > >> The overall direction and writeup for this looks good to me. I think > >> we need to be more specific about how doubles & floats fit into this > >> though as they are perpetual source of special cases. > > > > Indeed, floating point is the gift that keeps on giving. > > > > Joe recently did some nice work in the spec of Float and Double, > > outlining the various different ways in which floats can be compared. > > This allows language features like pattern matching, casting, and > > switch to appeal to "compared by FooBar comparison", rather than > > spelling it out for each use. > > > > > FYI, the new text in question is: > > > https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html#fpNumericalEq > > For the cases in the draft JEP, there have been separate discussions > working through the details. Putting aside how it might be implemented, > for the > > floating-point type -> integral type > > cases, conceptually if the same real number can be presented in the > floating-point type and the integral type, then the conversion is exact. > (While floating-point values are often thought of as "fuzzy," each > finite floating-point value represents some particular real number. > Finite binary floating-point values are sums of the powers of 2 where > the exponent difference of the powers is bounded by the significand > width of the floating-point format in question.) The main special case > is how conversion of -0.0 to an integral type is defined for purposes of > instanceof. The desired double -> float behavior can be inferred from > IEEE 754 concepts. > > HTH, > > -Joe > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Nov 16 15:20:38 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 16 Nov 2022 10:20:38 -0500 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: References: <7b362ea0-f93d-3cd6-d13f-568b17f6c852@oracle.com> Message-ID: Indeed.? During the early explorations for this feature we got fooled by values for which casting from T to U lost precision, but the corresponding cast back from U to T was also imprecise, and so the round-trip T -> U -> T preserved the input value.? We scratched our heads over this for a while. On 11/16/2022 10:15 AM, Dan Heidinga wrote: > It's good to hear that you and others are thinking through the details > on how float/doubles will work. > > I still have some concern with user-intuition when writing pattern > matching code over floating point values if users base their intuition > on their experience with widening casts to float.? There's a great > sample program (JLS Example 5.1.2-1) which shows the loss of precision > when casting a large int to a float which I would try to express with > pattern matching roughly as: > > record FloatBox(float f) {} > int big = 1234567890; > FloatBox box = new FloatBox(big); > if (box instanceof FloatBox(int i)) { > ? ?// pattern won't match here > } > > I think users would be surprised reading the code that the pattern > doesn't match because converting back to an int would lose precession. > > The equivalent non-pattern code would be pretty clear that it accepted > the loss of precession: > > if (box instanceof FLoatBox) { > ? int i = (int)box.f(); > ? .... > } > > Users will find it confusing when the pattern seems to match > "sometimes" though this is likely due to existing confusion related to > floating types.? Maybe expanding on the expected implementation will > make it easier to build a mental model for when the match will succeed? > > --Dan > > > On Tue, Nov 15, 2022 at 6:13 PM Joseph D. Darcy > wrote: > > On 11/15/2022 12:13 PM, Brian Goetz wrote: > > > > > > On 11/15/2022 2:55 PM, Dan Heidinga wrote: > >> Hi Angelos, > >> > >> The overall direction and writeup for this looks good to me.? I > think > >> we need to be more specific about how doubles & floats fit into > this > >> though as they are perpetual source of special cases. > > > > Indeed, floating point is the gift that keeps on giving. > > > > Joe recently did some nice work in the spec of Float and Double, > > outlining the various different ways in which floats can be > compared. > > This allows language features like pattern matching, casting, and > > switch to appeal to "compared by FooBar comparison", rather than > > spelling it out for each use. > > > > > FYI, the new text in question is: > > https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/lang/Double.html#fpNumericalEq > > > For the cases in the draft JEP, there have been separate discussions > working through the details. Putting aside how it might be > implemented, > for the > > ??? floating-point type -> integral type > > cases, conceptually if the same real number can be presented in the > floating-point type and the integral type, then the conversion is > exact. > (While floating-point values are often thought of as "fuzzy," each > finite floating-point value represents some particular real number. > Finite binary floating-point values are sums of the powers of 2 where > the exponent difference of the powers is bounded by the significand > width of the floating-point format in question.) The main special > case > is how conversion of -0.0 to an integral type is defined for > purposes of > instanceof. The desired double -> float behavior can be inferred from > IEEE 754 concepts. > > HTH, > > -Joe > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Nov 16 16:21:56 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 16 Nov 2022 11:21:56 -0500 Subject: Updated spec for String Templates (JEP 430) now available In-Reply-To: <454AD280-6F7E-4AB1-AB98-6AF677EE484E@oracle.com> References: <454AD280-6F7E-4AB1-AB98-6AF677EE484E@oracle.com> Message-ID: The spec seems fuzzy on how we perform the equivalent of indentation adjustment from text blocks.? Suppose I have ??? String s = STR.""" ??????? Hello \{name}, it is \{time} ??? """; This should result in the string "Hello Bob, it is 3:00".? My understanding of how it should work is something like: ?- replace all the embedded expressions with a placeholder character; ?- evaluate the resulting text block; ?- split the text block at the placeholder to produce the fragment literals. But the spec says only: > A template resembles a string literal or a text block but consists of > the strict alternate interleaving of two or more string literals or > text blocks, known as fragment literals, with one or more embedded > expressions. An embedded expression can be either empty or an expression. What is being interleaved is neither string literal nor text block, so the use of "string literal" and "text block" seems off here, and I don't see how the TextBlockTemplateFragment is processed for escapes and whitespace the way we would with a TextBlock.? So it seems a little work is needed here? From amaembo at gmail.com Wed Nov 16 16:50:55 2022 From: amaembo at gmail.com (Tagir Valeev) Date: Wed, 16 Nov 2022 17:50:55 +0100 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: References: Message-ID: Hello! >From what I see, `instanceof byte`, `instanceof short`, `instanceof char` and `instanceof int` applied to a wider integral value are four range-checking conditions. In many cases, people may want to check against different (but compile-time constant) range. It looks too restrictive to support only four specific ranges. I understand the rationale about symmetry between primitive and reference types but the usefulness looks very limited to me. Supporting custom ranges, like `instanceof int(>0) x` or `instanceof byte(0..100) b` or something like this (with dominance and exhaustiveness checks in switch) would be much more useful. I agree that this would also require much more work, but at least it would be nice to take this in mind as a possible future improvement. With best regards, Tagir Valeev. On Tue, Nov 15, 2022 at 12:20 AM Angelos Bimpoudis wrote: > > Dear experts, > > The draft JEP for adding support for primitive types in instanceof and type patterns, that has been previously discussed on this list, is available at: > > https://bugs.openjdk.org/browse/JDK-8288476 > > Suggestions are welcomed! > Angelos From brian.goetz at oracle.com Wed Nov 16 16:59:47 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 16 Nov 2022 11:59:47 -0500 Subject: Support for primitive types in instanceof and type patterns In-Reply-To: References: Message-ID: <5df722f3-de71-4cfa-590c-82469cf33e53@oracle.com> I agree and disagree. I agree that range checking of other ranges is useful and something that belongs on the "candidate features" list.? In fact, it's been on my list for a while. But I disagree that this is the time or place for it, or the best way to do it.? Range checking may be one way to view "instanceof byte", but a more general way is that is the precondition for safely casting to byte.? And the language defines casting rules not only from other integral types, but from floating point types as well. That said, we've been keeping our eye on ranges in general, since they are useful in lots of places besides patterns, such as: ??? // loops ??? for (int i : 1..10)? // we can argue over inclusive vs exclusive ??? for (int i : array.range())? // range returns a Range, which is Iterable ??? // case labels ??? case 1..10: ... We could do this today, but we could do better tomorrow with features coming from Valhalla.? This is how I'm thinking we'll get there. On 11/16/2022 11:50 AM, Tagir Valeev wrote: > Hello! > > From what I see, `instanceof byte`, `instanceof short`, `instanceof > char` and `instanceof int` applied to a wider integral value are four > range-checking conditions. In many cases, people may want to check > against different (but compile-time constant) range. It looks too > restrictive to support only four specific ranges. I understand the > rationale about symmetry between primitive and reference types but the > usefulness looks very limited to me. Supporting custom ranges, like > `instanceof int(>0) x` or `instanceof byte(0..100) b` or something > like this (with dominance and exhaustiveness checks in switch) would > be much more useful. I agree that this would also require much more > work, but at least it would be nice to take this in mind as a possible > future improvement. > > With best regards, > Tagir Valeev. > > On Tue, Nov 15, 2022 at 12:20 AM Angelos Bimpoudis > wrote: >> Dear experts, >> >> The draft JEP for adding support for primitive types in instanceof and type patterns, that has been previously discussed on this list, is available at: >> >> https://bugs.openjdk.org/browse/JDK-8288476 >> >> Suggestions are welcomed! >> Angelos -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Thu Nov 17 10:37:25 2022 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Thu, 17 Nov 2022 10:37:25 +0000 Subject: Updated spec for String Templates (JEP 430) now available In-Reply-To: References: <454AD280-6F7E-4AB1-AB98-6AF677EE484E@oracle.com> Message-ID: <40C96167-A45C-4AB2-B1BD-339BBAB58892@oracle.com> Thanks Brian: > On 16 Nov 2022, at 16:21, Brian Goetz wrote: > > The spec seems fuzzy on how we perform the equivalent of indentation adjustment from text blocks. Suppose I have > > String s = STR.""" > Hello \{name}, it is \{time} > """; > > This should result in the string "Hello Bob, it is 3:00". My understanding of how it should work is something like: > > - replace all the embedded expressions with a placeholder character; > - evaluate the resulting text block; > - split the text block at the placeholder to produce the fragment literals. > > But the spec says only: > >> A template resembles a string literal or a text block but consists of the strict alternate interleaving of two or more string literals or text blocks, known as fragment literals, with one or more embedded expressions. An embedded expression can be either empty or an expression. > > What is being interleaved is neither string literal nor text block, so the use of "string literal" and "text block" seems off here, and I don't see how the TextBlockTemplateFragment is processed for escapes and whitespace the way we would with a TextBlock. So it seems a little work is needed here? This needs some work, agreed, but what we are attempting here is a high-level description of what a template is, not its syntactic representation. An analogy might be how we talk about arguments in a method invocation. We just talk about "the arguments", and evaluating ?the arguments?. We don?t talk about there being a ?thing" starting with a left bracket containing expressions separated by commas etc. There is some non-normative text about how the grammar is intended to allow you to think of double-quote followed by string fragment followed by escaped expression etc as if it were a string literal followed by expression ? If you pull on this thread you end up saying ?oh this template denotes an alternating sequence of strings and expressions?. Perhaps ?denotes? is better than ?consists of?? Hope that helps? But you?re right - this section needs more work... Thanks, Gavin PS Just to share the pain: The problem with your description about the Hello Bob example is that it is a template expression. So, what?s that thing on the right? It?s not a literal, clearly. Do you want to say it?s an expression? If you do that then we have to unpick most of chapter 15, as it?s not a general expression - we don?t want you to use it anywhere else. The JLS works by making compile-time statements and run-time statements. Your statement about ?how it works? is clearly run time. What about compile time? What is it? The concrete reality is that it is sugar for a constructor call with the strings and embedded expressions that the parser has pulled out for you. But we don?t want to mandate anything about how any of this might be implemented - right? - so we have to make the description more abstract... From amaembo at gmail.com Mon Nov 28 19:56:34 2022 From: amaembo at gmail.com (Tagir Valeev) Date: Mon, 28 Nov 2022 19:56:34 -0000 Subject: Make 'package' and 'import' contextual keywords Message-ID: Hello! Recent discussion about contextual keywords emerged an opposite desire for me. As we already have many contextual keywords, why not expand this to old fullfledged keywords to return some names to the identifier namespace. I can think of 'import' and 'package' which are meaningful as a keywords only at top-level of Java file. Allowing variables with such names could be desired in some programs and should not break much. At least, I occasionally want to create variables with such names. What do you think? Ok, it's just a crazy idea. With best regards, Tagir Valeev -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Nov 28 20:05:56 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 28 Nov 2022 20:05:56 -0000 Subject: Make 'package' and 'import' contextual keywords In-Reply-To: References: Message-ID: I would not have predicted this coming from an IDE developer, so this is quite interesting. Doing this with the keywords that were added in 1.2, 1.4, and 5 (assert, enum, etc) would right some historical wrongs (but you know my opinions about over-rotating towards fixing mistakes of the past.). And then there?s `goto`... > On Nov 28, 2022, at 2:56 PM, Tagir Valeev wrote: > > Hello! > > Recent discussion about contextual keywords emerged an opposite desire for me. As we already have many contextual keywords, why not expand this to old fullfledged keywords to return some names to the identifier namespace. I can think of 'import' and 'package' which are meaningful as a keywords only at top-level of Java file. Allowing variables with such names could be desired in some programs and should not break much. At least, I occasionally want to create variables with such names. What do you think? Ok, it's just a crazy idea. > > With best regards, > Tagir Valeev From forax at univ-mlv.fr Mon Nov 28 21:39:05 2022 From: forax at univ-mlv.fr (Remi Forax) Date: Mon, 28 Nov 2022 21:39:05 -0000 Subject: Make 'package' and 'import' contextual keywords In-Reply-To: References: Message-ID: <529005617.55040079.1669671534399.JavaMail.zimbra@u-pem.fr> ----- Original Message ----- > From: "Brian Goetz" > To: "Tagir Valeev" > Cc: "amber-spec-experts" > Sent: Monday, November 28, 2022 9:05:51 PM > Subject: Re: Make 'package' and 'import' contextual keywords > I would not have predicted this coming from an IDE developer, so this is quite > interesting. IDEs are kind of rich, they keep the grammar around (or a reduced form the of grammar) to avoid to re-parse the whole file each time there is a new keystroke so contextual keywords are not an issue. > > Doing this with the keywords that were added in 1.2, 1.4, and 5 (assert, enum, > etc) would right some historical wrongs (but you know my opinions about > over-rotating towards fixing mistakes of the past.). @interface is for me the worst offender, anyway i agree. > > And then there?s `goto`... already reserved by John to express tail method calls :) > >> On Nov 28, 2022, at 2:56 PM, Tagir Valeev wrote: >> >> Hello! >> >> Recent discussion about contextual keywords emerged an opposite desire for me. >> As we already have many contextual keywords, why not expand this to old >> fullfledged keywords to return some names to the identifier namespace. I can >> think of 'import' and 'package' which are meaningful as a keywords only at >> top-level of Java file. Allowing variables with such names could be desired in >> some programs and should not break much. At least, I occasionally want to >> create variables with such names. What do you think? Ok, it's just a crazy >> idea. R?mi >> >> With best regards, > > Tagir Valeev