From forax at univ-mlv.fr Tue Feb 4 09:43:51 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 4 Feb 2025 10:43:51 +0100 (CET) Subject: import module and supply chain attacks Message-ID: <1535558629.92241961.1738662231156.JavaMail.zimbra@univ-eiffel.fr> Hello, I still think that adding the feature "import module" in the langage allows supply chain attacks than was not possible before. Disclaimer, i'm not a security researcher and i'm bad at it, i've created far more security issues than i've found them, anyway, i think i should speak up because in my opinion "import module" adds a whole new cans of worms. In Java, when a qualified names is resolved, the compiler first tries to see if its a class and then if its a package name (see https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.5.4), so adding a class in a package which is a prefix of an existing package can change the meaning of all classes in the existing package. By example, the class foo.bar.Baz exist, and one can introduce the class "bar" that contains a member class "Baz" in the package "foo", this class will be used instead of the existing class. Now, import modules can even import packages from a module which is not directly referenced in the source code, it follows the "require transitive", so an attacker can add a specily crafted class as decribed above in the dependencies and wait until the code using the dependency far down in the dependency tree is recompiled. Again, i'm not a security researcher, so i don't how bad this is, but it seems pretty bad to me. regards, R?mi From brian.goetz at oracle.com Tue Feb 4 09:48:05 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 4 Feb 2025 09:48:05 +0000 Subject: import module and supply chain attacks In-Reply-To: <1535558629.92241961.1738662231156.JavaMail.zimbra@univ-eiffel.fr> References: <1535558629.92241961.1738662231156.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <8072A92C-6720-4ABF-9160-02C1236740D5@oracle.com> Could you flesh out this idea with a before and after example? > On Feb 4, 2025, at 10:44?AM, Remi Forax wrote: > > ?Hello, > I still think that adding the feature "import module" in the langage allows supply chain attacks than was not possible before. > > Disclaimer, i'm not a security researcher and i'm bad at it, i've created far more security issues than i've found them, > anyway, i think i should speak up because in my opinion "import module" adds a whole new cans of worms. > > In Java, when a qualified names is resolved, the compiler first tries to see if its a class and then if its a package name > (see https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.5.4), > so adding a class in a package which is a prefix of an existing package can change the meaning of all classes in the existing package. > > By example, the class foo.bar.Baz exist, and one can introduce the class "bar" that contains a member class "Baz" in the package "foo", > this class will be used instead of the existing class. > > Now, import modules can even import packages from a module which is not directly referenced in the source code, it follows the "require transitive", > so an attacker can add a specily crafted class as decribed above in the dependencies and wait until the code using the dependency far down in the dependency tree is recompiled. > > Again, i'm not a security researcher, so i don't how bad this is, but it seems pretty bad to me. > > regards, > R?mi > > > From forax at univ-mlv.fr Tue Feb 4 10:01:55 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 4 Feb 2025 11:01:55 +0100 (CET) Subject: Remove the auto-static-import feature Message-ID: <1997597427.92273743.1738663315867.JavaMail.zimbra@univ-eiffel.fr> Hello Gavin, I'm back from FOSDEM where we had several discussions around the removal of the auto static-import feature. I believe this feature is necessary to "Help students write basic programs in a concise manner" but goes at odd with "Do not introduce a separate dialect of the Java language", so the question seem to be is which one of these goals in more important than the other. In blunt terms, do we think that Java can be teached as first langage instead of Python, if the answer is yes, then "println" should be "println" instead of "IO.println". Otherwise, we recognize that we just want to make Java easier to teach and in that case, i'm fine with remoing the auto static-import feature. regards, R?mi From forax at univ-mlv.fr Tue Feb 4 10:32:58 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 4 Feb 2025 11:32:58 +0100 (CET) Subject: Pattern matching on primitive types mxied with instanceof is a footgun Message-ID: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> Last week, one of the TA for the course "OOP using Java" was grading student projects, the subject of the project can be summarize to "you are alone in space and angry aliens want you to die". One of the project had a weird bug when displaying aliens. Spoiling the result of bug hunting, this is due to students using the pattern matching on primitive without them realizing it. Here is a reproducer of the bug: // in AlienSpaceship.java record AlienSpaceship(double x, double y) implements Spaceship { ... } ... // in a method in another class ... for(Spaceship spacehip : ...) { ... if (spaceship instanceof AlienSpaceship(int x, int y) { // display the alien space ship at (x, y) } ... } The TA said she was about to give up when she found the issue and that the Java spec should not allow such pattern. I agree with here, pattern matching on primitive types is not a feature people ask for and mixed with instanceof it's a footgun. This feature can be re-introduced later using method patterns and it will be easier to understand the code, by example with an hyphotethical method Double.asInt if (spaceship instanceof AlienSpaceship(Double.asInt(int x), Double.asInt(int y)) { ... regards, R?mi From brian.goetz at oracle.com Tue Feb 4 11:44:53 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 4 Feb 2025 11:44:53 +0000 Subject: Pattern matching on primitive types mxied with instanceof is a footgun In-Reply-To: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> Wow, that was pretty amazing. You went from ?one student, who was never taught about how this works, was confused by it? to ? let?s pull the whole feature ? in one breath. > On Feb 4, 2025, at 11:33?AM, Remi Forax wrote: > > ?Last week, > one of the TA for the course "OOP using Java" was grading student projects, > the subject of the project can be summarize to "you are alone in space and angry aliens want you to die". > > One of the project had a weird bug when displaying aliens. > Spoiling the result of bug hunting, this is due to students using the pattern matching on primitive without them realizing it. > > Here is a reproducer of the bug: > > // in AlienSpaceship.java > record AlienSpaceship(double x, double y) implements Spaceship { > ... > } > > ... > > // in a method in another class > ... > for(Spaceship spacehip : ...) { > ... > if (spaceship instanceof AlienSpaceship(int x, int y) { > // display the alien space ship at (x, y) > } > ... > } > > The TA said she was about to give up when she found the issue and that the Java spec should not allow such pattern. > I agree with here, pattern matching on primitive types is not a feature people ask for and mixed with instanceof it's a footgun. > > This feature can be re-introduced later using method patterns and it will be easier to understand the code, > by example with an hyphotethical method Double.asInt > > if (spaceship instanceof AlienSpaceship(Double.asInt(int x), Double.asInt(int y)) { > ... > > regards, > R?mi From amaembo at gmail.com Tue Feb 4 16:00:56 2025 From: amaembo at gmail.com (Tagir Valeev) Date: Tue, 4 Feb 2025 17:00:56 +0100 Subject: Pattern matching on primitive types mxied with instanceof is a footgun In-Reply-To: <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> Message-ID: Hello! Well, I would say that Remi has a point. This is a silent mistake that can be made. You don't see the declaration, as it's in another file so you may forget about original types and assume that they are ints. The code compiles and doesn't even throw an exception, it just works incorrectly. It would be justified if such code pattern (converting from double to int only when double fits the int) was common, so conditional narrowing could be useful in many other places. But the fact is that it's highly uncommon. Nobody does this. Many other pattern matching features are nice. E.g., I often see the code which can be migrated to pattern switch (we are still on Java 17) and I really want to use it. However, I never see the code which can be migrated to a narrowing primitive pattern. I don't agree that we should drop primitive patterns completely, but we may reconsider floating point <-> integral conversions and disable them in patterns for a while (enabling them back later will be always possible). With best regards, Tagir Valeev On Tue, Feb 4, 2025 at 12:45?PM Brian Goetz wrote: > Wow, that was pretty amazing. You went from ?one student, who was never > taught about how this works, was confused by it? to ? let?s pull the whole > feature ? in one breath. > > > On Feb 4, 2025, at 11:33?AM, Remi Forax wrote: > > > > ?Last week, > > one of the TA for the course "OOP using Java" was grading student > projects, > > the subject of the project can be summarize to "you are alone in space > and angry aliens want you to die". > > > > One of the project had a weird bug when displaying aliens. > > Spoiling the result of bug hunting, this is due to students using the > pattern matching on primitive without them realizing it. > > > > Here is a reproducer of the bug: > > > > // in AlienSpaceship.java > > record AlienSpaceship(double x, double y) implements Spaceship { > > ... > > } > > > > ... > > > > // in a method in another class > > ... > > for(Spaceship spacehip : ...) { > > ... > > if (spaceship instanceof AlienSpaceship(int x, int y) { > > // display the alien space ship at (x, y) > > } > > ... > > } > > > > The TA said she was about to give up when she found the issue and that > the Java spec should not allow such pattern. > > I agree with here, pattern matching on primitive types is not a feature > people ask for and mixed with instanceof it's a footgun. > > > > This feature can be re-introduced later using method patterns and it > will be easier to understand the code, > > by example with an hyphotethical method Double.asInt > > > > if (spaceship instanceof AlienSpaceship(Double.asInt(int x), > Double.asInt(int y)) { > > ... > > > > regards, > > R?mi > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Tue Feb 4 16:55:36 2025 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 4 Feb 2025 16:55:36 +0000 Subject: Pattern matching on primitive types mxied with instanceof is a footgun In-Reply-To: References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> Message-ID: Hi, would some of the comments in this thread change if the example was more like: AlienSpaceShip ship = ... int x = (int)ship.getX(); This works and no error is issued. From a design perspective, the above code is basically what the record pattern is supposed to desugar to - in other words, pattern matching is precondition for safe cast. For primitives, determining whether a cast is "safe" involves a runtime range check, which is invoked by the compiler. So ``` jshell> double d = 4.2; d ==> 4.2 jshell> d instanceof int $2 ==> false jshell> double d = 4.0; d ==> 4.0 jshell> d instanceof int $4 ==> true ``` This seems consistent. So the question is: what is the "mistake" we're talking about here? The user thinking it was a _unconditional_ match where in reality that's not the case? While in the case of instanceof unconditionality is harder to spot, if this was a switch, the compiler would have immediately asked the user to provide a default? It seems to me that the reasoning here implies that developers will use "if" + "instanceof" _without an "else" just for the purpose of extract some data, and then complain when the thing doesn't match (because they have no "else", and so their code will fail). It seems like our best weapon in this case is education, rather that introducing arbitrary restrictions and asymmetries in the language? (Or, perhaps, in the future have a way to perform an _unconditional_ extraction without an "if", in which case the compiler will bark if the pattern is not unconditional.) Maurizio On 04/02/2025 16:00, Tagir Valeev wrote: > Hello! > > Well, I would say that Remi has a point. This is a silent mistake that > can be made. You don't see the declaration, as it's in another file so > you may forget about original types and assume that they are ints. The > code compiles and doesn't even throw an exception, it just works > incorrectly. It would be justified if such code pattern (converting > from double to int only when double fits the int) was common, so > conditional narrowing could be useful in many other places. But the > fact is that it's highly uncommon. Nobody does this. Many other > pattern matching features are nice. E.g., I often see the code which > can be migrated to pattern switch (we are still on Java 17) and I > really want to use it. However, I never see the code which can be > migrated to a narrowing primitive pattern. > > I don't agree that we should drop primitive patterns completely, but > we may reconsider floating point <-> integral conversions and disable > them in patterns for a while (enabling them back later will be always > possible). > > With best regards, > Tagir Valeev > > On Tue, Feb 4, 2025 at 12:45?PM Brian Goetz > wrote: > > Wow, that was pretty amazing. You went from ?one student, who was > never taught about how this works, was confused by it? to ? let?s > pull the whole feature ? in one breath. > > > On Feb 4, 2025, at 11:33?AM, Remi Forax wrote: > > > > ?Last week, > > one of the TA for the course "OOP using Java" was grading > student projects, > > the subject of the project can be summarize to "you are alone in > space and angry aliens want you to die". > > > > One of the project had a weird bug when displaying aliens. > > Spoiling the result of bug hunting, this is due to students > using the pattern matching on primitive without them realizing it. > > > > Here is a reproducer of the bug: > > > > // in AlienSpaceship.java > > record AlienSpaceship(double x, double y) implements Spaceship { > >? ... > > } > > > > ... > > > > // in a method in another class > >? ... > >? for(Spaceship spacehip : ...) { > >? ? ... > >? ? if (spaceship instanceof AlienSpaceship(int x, int y) { > >? ? ? // display the alien space ship at (x, y) > >? ? } > >? ? ... > >? } > > > > The TA said she was about to give up when she found the issue > and that the Java spec should not allow such pattern. > > I agree with here, pattern matching on primitive types is not a > feature people ask for and mixed with instanceof it's a footgun. > > > > This feature can be re-introduced later using method patterns > and it will be easier to understand the code, > > by example with an hyphotethical method Double.asInt > > > >? if (spaceship instanceof AlienSpaceship(Double.asInt(int x), > Double.asInt(int y)) { > >? ? ... > > > > regards, > > R?mi > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Tue Feb 4 17:08:57 2025 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Tue, 4 Feb 2025 17:08:57 +0000 Subject: Pattern matching on primitive types mxied with instanceof is a footgun In-Reply-To: References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> Message-ID: <1B0DCC3B-F138-42A6-9E94-0C5E8F4F7E6A@oracle.com> One good technique is to always favour `var` patterns; then you don?t get any unwanted tests, i.e. for(Spaceship spaceship : ...) { ... if (spaceship instanceof AlienSpaceship(var x, var y) { // display the alien space ship at (x, y) } ... } Gavin On 4 Feb 2025, at 16:55, Maurizio Cimadamore wrote: Hi, would some of the comments in this thread change if the example was more like: AlienSpaceShip ship = ... int x = (int)ship.getX(); This works and no error is issued. From a design perspective, the above code is basically what the record pattern is supposed to desugar to - in other words, pattern matching is precondition for safe cast. For primitives, determining whether a cast is "safe" involves a runtime range check, which is invoked by the compiler. So ``` jshell> double d = 4.2; d ==> 4.2 jshell> d instanceof int $2 ==> false jshell> double d = 4.0; d ==> 4.0 jshell> d instanceof int $4 ==> true ``` This seems consistent. So the question is: what is the "mistake" we're talking about here? The user thinking it was a _unconditional_ match where in reality that's not the case? While in the case of instanceof unconditionality is harder to spot, if this was a switch, the compiler would have immediately asked the user to provide a default? It seems to me that the reasoning here implies that developers will use "if" + "instanceof" _without an "else" just for the purpose of extract some data, and then complain when the thing doesn't match (because they have no "else", and so their code will fail). It seems like our best weapon in this case is education, rather that introducing arbitrary restrictions and asymmetries in the language? (Or, perhaps, in the future have a way to perform an _unconditional_ extraction without an "if", in which case the compiler will bark if the pattern is not unconditional.) Maurizio On 04/02/2025 16:00, Tagir Valeev wrote: Hello! Well, I would say that Remi has a point. This is a silent mistake that can be made. You don't see the declaration, as it's in another file so you may forget about original types and assume that they are ints. The code compiles and doesn't even throw an exception, it just works incorrectly. It would be justified if such code pattern (converting from double to int only when double fits the int) was common, so conditional narrowing could be useful in many other places. But the fact is that it's highly uncommon. Nobody does this. Many other pattern matching features are nice. E.g., I often see the code which can be migrated to pattern switch (we are still on Java 17) and I really want to use it. However, I never see the code which can be migrated to a narrowing primitive pattern. I don't agree that we should drop primitive patterns completely, but we may reconsider floating point <-> integral conversions and disable them in patterns for a while (enabling them back later will be always possible). With best regards, Tagir Valeev On Tue, Feb 4, 2025 at 12:45?PM Brian Goetz > wrote: Wow, that was pretty amazing. You went from ?one student, who was never taught about how this works, was confused by it? to ? let?s pull the whole feature ? in one breath. > On Feb 4, 2025, at 11:33?AM, Remi Forax > wrote: > > ?Last week, > one of the TA for the course "OOP using Java" was grading student projects, > the subject of the project can be summarize to "you are alone in space and angry aliens want you to die". > > One of the project had a weird bug when displaying aliens. > Spoiling the result of bug hunting, this is due to students using the pattern matching on primitive without them realizing it. > > Here is a reproducer of the bug: > > // in AlienSpaceship.java > record AlienSpaceship(double x, double y) implements Spaceship { > ... > } > > ... > > // in a method in another class > ... > for(Spaceship spacehip : ...) { > ... > if (spaceship instanceof AlienSpaceship(int x, int y) { > // display the alien space ship at (x, y) > } > ... > } > > The TA said she was about to give up when she found the issue and that the Java spec should not allow such pattern. > I agree with here, pattern matching on primitive types is not a feature people ask for and mixed with instanceof it's a footgun. > > This feature can be re-introduced later using method patterns and it will be easier to understand the code, > by example with an hyphotethical method Double.asInt > > if (spaceship instanceof AlienSpaceship(Double.asInt(int x), Double.asInt(int y)) { > ... > > regards, > R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb9n at gmail.com Tue Feb 4 17:14:53 2025 From: kevinb9n at gmail.com (Kevin Bourrillion) Date: Tue, 4 Feb 2025 09:14:53 -0800 Subject: Pattern matching on primitive types mxied with instanceof is a footgun In-Reply-To: References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> Message-ID: On Tue, Feb 4, 2025 at 8:55?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > This seems consistent. So the question is: what is the "mistake" we're > talking about here? The user thinking it was a _unconditional_ match where > in reality that's not the case? While in the case of instanceof > unconditionality is harder to spot, if this was a switch, the compiler > would have immediately asked the user to provide a default? > > It seems to me that the reasoning here implies that developers will use > "if" + "instanceof" _without an "else" just for the purpose of extract some > data, and then complain when the thing doesn't match (because they have no > "else", and so their code will fail). It seems like our best weapon in this > case is education, rather that introducing arbitrary restrictions and > asymmetries in the language? > > (Or, perhaps, in the future have a way to perform an _unconditional_ > extraction without an "if", in which case the compiler will bark if the > pattern is not unconditional.) > In some cases this will be relevant, but in *this *particular example we're looping over Spaceship and then checking for AlienSpaceship, so, no help. I think it is fair to acknowledge that this is a weakness of the feature design. How to mitigate it? We can try to evangelize always preferring `var` for nested type patterns that are expected to be unconditional. That's an unfortunate readability trade-off, though. And a static analyzer can't know whether you expected it to be unconditional or not, so there might not be much it can do to help. I am not even sure what language change could be considered here. Note that this problem is not specific to primitive types, it's just that primitive types are currently the only ones that support "value conversion" so we're encountering this issue with them first. Post-Valhalla, other types might support value conversion too. On 04/02/2025 16:00, Tagir Valeev wrote: > > Hello! > > Well, I would say that Remi has a point. This is a silent mistake that can > be made. You don't see the declaration, as it's in another file so you may > forget about original types and assume that they are ints. The code > compiles and doesn't even throw an exception, it just works incorrectly. It > would be justified if such code pattern (converting from double to int only > when double fits the int) was common, so conditional narrowing could be > useful in many other places. But the fact is that it's highly uncommon. > Nobody does this. Many other pattern matching features are nice. E.g., I > often see the code which can be migrated to pattern switch (we are still on > Java 17) and I really want to use it. However, I never see the code which > can be migrated to a narrowing primitive pattern. > > I don't agree that we should drop primitive patterns completely, but we > may reconsider floating point <-> integral conversions and disable them in > patterns for a while (enabling them back later will be always possible). > > With best regards, > Tagir Valeev > > On Tue, Feb 4, 2025 at 12:45?PM Brian Goetz > wrote: > >> Wow, that was pretty amazing. You went from ?one student, who was never >> taught about how this works, was confused by it? to ? let?s pull the whole >> feature ? in one breath. >> >> > On Feb 4, 2025, at 11:33?AM, Remi Forax wrote: >> > >> > ?Last week, >> > one of the TA for the course "OOP using Java" was grading student >> projects, >> > the subject of the project can be summarize to "you are alone in space >> and angry aliens want you to die". >> > >> > One of the project had a weird bug when displaying aliens. >> > Spoiling the result of bug hunting, this is due to students using the >> pattern matching on primitive without them realizing it. >> > >> > Here is a reproducer of the bug: >> > >> > // in AlienSpaceship.java >> > record AlienSpaceship(double x, double y) implements Spaceship { >> > ... >> > } >> > >> > ... >> > >> > // in a method in another class >> > ... >> > for(Spaceship spacehip : ...) { >> > ... >> > if (spaceship instanceof AlienSpaceship(int x, int y) { >> > // display the alien space ship at (x, y) >> > } >> > ... >> > } >> > >> > The TA said she was about to give up when she found the issue and that >> the Java spec should not allow such pattern. >> > I agree with here, pattern matching on primitive types is not a feature >> people ask for and mixed with instanceof it's a footgun. >> > >> > This feature can be re-introduced later using method patterns and it >> will be easier to understand the code, >> > by example with an hyphotethical method Double.asInt >> > >> > if (spaceship instanceof AlienSpaceship(Double.asInt(int x), >> Double.asInt(int y)) { >> > ... >> > >> > regards, >> > R?mi >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephan.herrmann at berlin.de Tue Feb 4 21:57:32 2025 From: stephan.herrmann at berlin.de (Stephan Herrmann) Date: Tue, 4 Feb 2025 22:57:32 +0100 Subject: Pattern matching on primitive types mxied with instanceof is a footgun In-Reply-To: <1B0DCC3B-F138-42A6-9E94-0C5E8F4F7E6A@oracle.com> References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> <1B0DCC3B-F138-42A6-9E94-0C5E8F4F7E6A@oracle.com> Message-ID: <46a5b70b-b5b1-49e8-b84c-f9628c4b92c1@berlin.de> As part of educating people to prefer var in such cases, compilers/linters could issue a warning when a nested primitive pattern is conditional. IDEs would then offer to resolve the issue by changing to var or to the exact type. Stephan Am 04.02.25 um 18:08 schrieb Gavin Bierman: > One good technique is to always favour `var` patterns; then you don?t get any > unwanted tests, i.e. > > for(Spaceship spaceship : ...) { > ? ?... > ? ?if (spaceship instanceof AlienSpaceship(var x, var y) { > ? ? ?// display the alien space ship at (x, y) > ? ?} > ? ?... > ?} > > Gavin > >> On 4 Feb 2025, at 16:55, Maurizio Cimadamore >> wrote: >> >> Hi, >> would some of the comments in this thread change if the example was more like: >> >> AlienSpaceShip ship = ... >> int x = (int)ship.getX(); >> >> This works and no error is issued. >> >> From a design perspective, the above code is basically what the record pattern >> is supposed to desugar to - in other words, pattern matching is precondition >> for safe cast. For primitives, determining whether a cast is "safe" involves a >> runtime range check, which is invoked by the compiler. >> >> So >> >> ``` >> jshell> double d = 4.2; >> d ==> 4.2 >> >> jshell> d instanceof int >> $2 ==> false >> >> jshell> double d = 4.0; >> d ==> 4.0 >> >> jshell> d instanceof int >> $4 ==> true >> ``` >> >> This seems consistent. So the question is: what is the "mistake" we're talking >> about here? The user thinking it was a _unconditional_ match where in reality >> that's not the case? While in the case of instanceof unconditionality is >> harder to spot, if this was a switch, the compiler would have immediately >> asked the user to provide a default? >> >> It seems to me that the reasoning here implies that developers will use "if" + >> "instanceof" _without an "else" just for the purpose of extract some data, and >> then complain when the thing doesn't match (because they have no "else", and >> so their code will fail). It seems like our best weapon in this case is >> education, rather that introducing arbitrary restrictions and asymmetries in >> the language? >> >> (Or, perhaps, in the future have a way to perform an _unconditional_ >> extraction without an "if", in which case the compiler will bark if the >> pattern is not unconditional.) >> >> Maurizio >> >> On 04/02/2025 16:00, Tagir Valeev wrote: >>> Hello! >>> >>> Well, I would say that Remi has a point. This is a silent mistake that can be >>> made. You don't see the declaration, as it's in another file so you may >>> forget about original types and assume that they are ints. The code compiles >>> and doesn't even throw an exception, it just works incorrectly. It would be >>> justified if such code pattern (converting from double to int only when >>> double fits the int) was common, so conditional narrowing could be useful in >>> many other places. But the fact is that it's highly uncommon. Nobody does >>> this. Many other pattern matching features are nice. E.g., I often see the >>> code which can be migrated to pattern switch (we are still on Java 17) and I >>> really want to use it. However, I never see the code which can be migrated to >>> a narrowing primitive pattern. >>> >>> I don't agree that we should drop primitive patterns completely, but we may >>> reconsider floating point <-> integral conversions and disable them in >>> patterns for a while (enabling them back later will be always possible). >>> >>> With best regards, >>> Tagir Valeev >>> >>> On Tue, Feb 4, 2025 at 12:45?PM Brian Goetz wrote: >>> >>> Wow, that was pretty amazing. You went from ?one student, who was never >>> taught about how this works, was confused by it? to ? let?s pull the >>> whole feature ? in one breath. >>> >>> > On Feb 4, 2025, at 11:33?AM, Remi Forax wrote: >>> > >>> > ?Last week, >>> > one of the TA for the course "OOP using Java" was grading student projects, >>> > the subject of the project can be summarize to "you are alone in space >>> and angry aliens want you to die". >>> > >>> > One of the project had a weird bug when displaying aliens. >>> > Spoiling the result of bug hunting, this is due to students using the >>> pattern matching on primitive without them realizing it. >>> > >>> > Here is a reproducer of the bug: >>> > >>> > // in AlienSpaceship.java >>> > record AlienSpaceship(double x, double y) implements Spaceship { >>> >? ... >>> > } >>> > >>> > ... >>> > >>> > // in a method in another class >>> >? ... >>> >? for(Spaceship spacehip : ...) { >>> >? ? ... >>> >? ? if (spaceship instanceof AlienSpaceship(int x, int y) { >>> >? ? ? // display the alien space ship at (x, y) >>> >? ? } >>> >? ? ... >>> >? } >>> > >>> > The TA said she was about to give up when she found the issue and that >>> the Java spec should not allow such pattern. >>> > I agree with here, pattern matching on primitive types is not a feature >>> people ask for and mixed with instanceof it's a footgun. >>> > >>> > This feature can be re-introduced later using method patterns and it >>> will be easier to understand the code, >>> > by example with an hyphotethical method Double.asInt >>> > >>> >? if (spaceship instanceof AlienSpaceship(Double.asInt(int x), >>> Double.asInt(int y)) { >>> >? ? ... >>> > >>> > regards, >>> > R?mi >>> > From forax at univ-mlv.fr Tue Feb 4 22:44:22 2025 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 4 Feb 2025 23:44:22 +0100 (CET) Subject: Pattern matching on primitive types mxied with instanceof is a footgun In-Reply-To: References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> Message-ID: <52763757.93823347.1738709062552.JavaMail.zimbra@univ-eiffel.fr> > From: "Kevin Bourrillion" > To: "Maurizio Cimadamore" > Cc: "Tagir Valeev" , "Brian Goetz" , > "Remi Forax" , "amber-spec-experts" > > Sent: Tuesday, February 4, 2025 6:14:53 PM > Subject: Re: Pattern matching on primitive types mxied with instanceof is a > footgun > On Tue, Feb 4, 2025 at 8:55 AM Maurizio Cimadamore < [ > mailto:maurizio.cimadamore at oracle.com | maurizio.cimadamore at oracle.com ] > > wrote: >> This seems consistent. So the question is: what is the "mistake" we're talking >> about here? The user thinking it was a _unconditional_ match where in reality >> that's not the case? While in the case of instanceof unconditionality is harder >> to spot, if this was a switch, the compiler would have immediately asked the >> user to provide a default? >> It seems to me that the reasoning here implies that developers will use "if" + >> "instanceof" _without an "else" just for the purpose of extract some data, and >> then complain when the thing doesn't match (because they have no "else", and so >> their code will fail). It seems like our best weapon in this case is education, >> rather that introducing arbitrary restrictions and asymmetries in the language? >> (Or, perhaps, in the future have a way to perform an _unconditional_ extraction >> without an "if", in which case the compiler will bark if the pattern is not >> unconditional.) > In some cases this will be relevant, but in this particular example we're > looping over Spaceship and then checking for AlienSpaceship, so, no help. > I think it is fair to acknowledge that this is a weakness of the feature design. > How to mitigate it? We can try to evangelize always preferring `var` for nested > type patterns that are expected to be unconditional. That's an unfortunate > readability trade-off, though. And a static analyzer can't know whether you > expected it to be unconditional or not, so there might not be much it can do to > help. > I am not even sure what language change could be considered here. Note that this > problem is not specific to primitive types, it's just that primitive types are > currently the only ones that support "value conversion" so we're encountering > this issue with them first. Post-Valhalla, other types might support value > conversion too. For me it's more about the conversion being implicit vs explicit. Here, we have an implicit conversion while the conversion does not always succeed. I believe such conversions, the one that may not always succeed, should be explicit not implicit. regards, R?mi @Brian, i'm more worry about a TA with more than 10 years of experience having trouble to find a bug in a student project written in Java. @Tagir, i'm not sure usin floating point values is the issue here, you can have the same kind of bug between a character and an int. >> On 04/02/2025 16:00, Tagir Valeev wrote: >>> Hello! >>> Well, I would say that Remi has a point. This is a silent mistake that can be >>> made. You don't see the declaration, as it's in another file so you may forget >>> about original types and assume that they are ints. The code compiles and >>> doesn't even throw an exception, it just works incorrectly. It would be >>> justified if such code pattern (converting from double to int only when double >>> fits the int) was common, so conditional narrowing could be useful in many >>> other places. But the fact is that it's highly uncommon. Nobody does this. Many >>> other pattern matching features are nice. E.g., I often see the code which can >>> be migrated to pattern switch (we are still on Java 17) and I really want to >>> use it. However, I never see the code which can be migrated to a narrowing >>> primitive pattern. >>> I don't agree that we should drop primitive patterns completely, but we may >>> reconsider floating point <-> integral conversions and disable them in patterns >>> for a while (enabling them back later will be always possible). >>> With best regards, >>> Tagir Valeev >>> On Tue, Feb 4, 2025 at 12:45 PM Brian Goetz < [ mailto:brian.goetz at oracle.com | >>> brian.goetz at oracle.com ] > wrote: >>>> Wow, that was pretty amazing. You went from ?one student, who was never taught >>>> about how this works, was confused by it? to ? let?s pull the whole feature ? >>>> in one breath. >>>>> On Feb 4, 2025, at 11:33 AM, Remi Forax < [ mailto:forax at univ-mlv.fr | >>>> > forax at univ-mlv.fr ] > wrote: >>>> > Last week, >>>> > one of the TA for the course "OOP using Java" was grading student projects, >>>>> the subject of the project can be summarize to "you are alone in space and angry >>>> > aliens want you to die". >>>> > One of the project had a weird bug when displaying aliens. >>>>> Spoiling the result of bug hunting, this is due to students using the pattern >>>> > matching on primitive without them realizing it. >>>> > Here is a reproducer of the bug: >>>> > // in AlienSpaceship.java >>>> > record AlienSpaceship(double x, double y) implements Spaceship { >>>> > ... >>>> > } >>>> > ... >>>> > // in a method in another class >>>> > ... >>>> > for(Spaceship spacehip : ...) { >>>> > ... >>>> > if (spaceship instanceof AlienSpaceship(int x, int y) { >>>> > // display the alien space ship at (x, y) >>>> > } >>>> > ... >>>> > } >>>>> The TA said she was about to give up when she found the issue and that the Java >>>> > spec should not allow such pattern. >>>>> I agree with here, pattern matching on primitive types is not a feature people >>>> > ask for and mixed with instanceof it's a footgun. >>>>> This feature can be re-introduced later using method patterns and it will be >>>> > easier to understand the code, >>>> > by example with an hyphotethical method Double.asInt >>>>> if (spaceship instanceof AlienSpaceship(Double.asInt(int x), Double.asInt(int >>>> > y)) { >>>> > ... >>>> > regards, >>>> > R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Feb 5 06:24:05 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 5 Feb 2025 06:24:05 +0000 Subject: Someone is confused by pattern matching (was: Pattern matching on primitive types mxied with instanceof is a footgun) In-Reply-To: <52763757.93823347.1738709062552.JavaMail.zimbra@univ-eiffel.fr> References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> <52763757.93823347.1738709062552.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Let?s dig in and see if we can find what?s really bothering you here. (But, the clickbait subject and the escalation from ?someone was confused? to ?so let?s take it out? is surely not helping, so let?s leave that behind.) For me it's more about the conversion being implicit vs explicit. But, I?m not seeing an implicit conversion. I?m seeing an *explicit* one. If I say float f = ? Int i = f The conversion here is both implicit and *lossy*. (I would be sympathetic if you were saying that lossy assignment conversion was troubling; this is a feature that we copied too-literally from C, and this is arguably a mistake.). But if I say If (f instanceof int i) { ? } The conversion looks pretty explicit to me, and it is never lossy. This is strictly better than either of the alternatives (don?t allow the pattern match at all, in which case the only conversion available to the user is an unsafe cast, or always allow it but accept silent information loss.). Further, I think a great deal of the discomfort here is that we?re still getting used to it. The old way was both inflexible and unsafe, so we?ve gotten used to the idea that ?everything about primitives is different.? Valhalla will bust that wide open soon enough anyway, so there?s no point in trying to cling to the old intuitions about primitives. The other feature involved is pattern nesting, which is composition; x matches P(Q) when x matches P(a) && a matches q. We discussed the concerns over ?action at a distance? endlessly in the first go-around; some people were concerned that Box b = ? If (b instanceof Box(String s)) { ? } Was too subtle, because the declaration and the use of the pattern were ?far away? and a reader might not see the conditionality of the nested pattern. I?m sympathetic to that, but (a) this is something that one grows more comfortable with with use, (b) IDEs can help by coloring conditional nested patterns differently, (c) the alternative is far less expressive. What we?re seeing now is merely composing these two features; there?s nothing new here, except that the visual ambiguity between ?just unpack the pattern? and ?do a nested match? gets combined with the novelty of primitive patterns (which again, take some time getting used to.) I can see how you would call this an ?implicit? conversion, but it?s not any more implicit with primitives as it is with Box(String s). So I recommend you think long and hard about what is *really* bothering you, and then we can have a conversation about it. Here, we have an implicit conversion while the conversion does not always succeed. I believe such conversions, the one that may not always succeed, should be explicit not implicit. regards, R?mi @Brian, i'm more worry about a TA with more than 10 years of experience having trouble to find a bug in a student project written in Java. @Tagir, i'm not sure usin floating point values is the issue here, you can have the same kind of bug between a character and an int. On 04/02/2025 16:00, Tagir Valeev wrote: Hello! Well, I would say that Remi has a point. This is a silent mistake that can be made. You don't see the declaration, as it's in another file so you may forget about original types and assume that they are ints. The code compiles and doesn't even throw an exception, it just works incorrectly. It would be justified if such code pattern (converting from double to int only when double fits the int) was common, so conditional narrowing could be useful in many other places. But the fact is that it's highly uncommon. Nobody does this. Many other pattern matching features are nice. E.g., I often see the code which can be migrated to pattern switch (we are still on Java 17) and I really want to use it. However, I never see the code which can be migrated to a narrowing primitive pattern. I don't agree that we should drop primitive patterns completely, but we may reconsider floating point <-> integral conversions and disable them in patterns for a while (enabling them back later will be always possible). With best regards, Tagir Valeev On Tue, Feb 4, 2025 at 12:45?PM Brian Goetz > wrote: Wow, that was pretty amazing. You went from ?one student, who was never taught about how this works, was confused by it? to ? let?s pull the whole feature ? in one breath. > On Feb 4, 2025, at 11:33?AM, Remi Forax > wrote: > > Last week, > one of the TA for the course "OOP using Java" was grading student projects, > the subject of the project can be summarize to "you are alone in space and angry aliens want you to die". > > One of the project had a weird bug when displaying aliens. > Spoiling the result of bug hunting, this is due to students using the pattern matching on primitive without them realizing it. > > Here is a reproducer of the bug: > > // in AlienSpaceship.java > record AlienSpaceship(double x, double y) implements Spaceship { > ... > } > > ... > > // in a method in another class > ... > for(Spaceship spacehip : ...) { > ... > if (spaceship instanceof AlienSpaceship(int x, int y) { > // display the alien space ship at (x, y) > } > ... > } > > The TA said she was about to give up when she found the issue and that the Java spec should not allow such pattern. > I agree with here, pattern matching on primitive types is not a feature people ask for and mixed with instanceof it's a footgun. > > This feature can be re-introduced later using method patterns and it will be easier to understand the code, > by example with an hyphotethical method Double.asInt > > if (spaceship instanceof AlienSpaceship(Double.asInt(int x), Double.asInt(int y)) { > ... > > regards, > R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Feb 5 06:55:52 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 5 Feb 2025 06:55:52 +0000 Subject: Someone is confused by pattern matching (was: Pattern matching on primitive types mxied with instanceof is a footgun) In-Reply-To: References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> <52763757.93823347.1738709062552.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <47003A5B-BE9B-4BCD-8F6F-D47045945829@oracle.com> Let me address Tagir?s points: > On Feb 4, 2025, at 5:00 PM, Tagir Valeev wrote: > > Well, I would say that Remi has a point. This is a silent mistake that can be made. Agree, the construct can be used incorrectly; in this case the user thought something different from what was going to happen. It is not clear what they thought was going to happen, though; perhaps they mistakenly thought that the coordinates were ints, or perhaps they mistakenly thought that the floats would be lossily converted to ints, as would happen with an assignment or blind cast. If we don?t know what mistake they were making, it?s hard to correct for that (and even harder to correct for both.) > You don't see the declaration, as it's in another file so you may forget about original types and assume that they are ints. Yes, we discussed this a lot when we did record patterns. But I must point out here: this has absolutely zero to do with primitive patterns. It just so happened that in this example, primitives were used, but one could make the same mistake with a Box and a nested `String` pattern. > The code compiles and doesn't even throw an exception, it just works incorrectly. Here is where I disagree! It does work correctly! It asks whether the coordinates can be safely converted to integers, and only proceeds if that is the case. And that is a totally reasonable and useful question to ask! It is just that this is not what the user *thought* was going to happen (and, see above, we?re not even sure which mistake the user made). But what the user thought here is only one reasonable way to interpret what should happen. You could argue that this syntax is too ?terse?, and this is the source of the problem; we could have specified nesting to require a claim of totality or partiality: case Box(partial String s): case Box(total Object o): But I don?t think anyone would have thanked us for that explicitness. (And if the markers were optional, the mistake could still happen.) > It would be justified if such code pattern (converting from double to int only when double fits the int) was common, so conditional narrowing could be useful in many other places. But the fact is that it's highly uncommon. Nobody does this. Many other pattern matching features are nice. E.g., I often see the code which can be migrated to pattern switch (we are still on Java 17) and I really want to use it. However, I never see the code which can be migrated to a narrowing primitive pattern. > > I don't agree that we should drop primitive patterns completely, but we may reconsider floating point <-> integral conversions and disable them in patterns for a while (enabling them back later will be always possible). Both of these arguments are dangerous arguments; they argue to introduce arbitrary asymmetries in how it works, just to match our guesses about ?what users think.? In the first case, you?re saying that we should forever treat primitives differently from objects (because they work differently today and we have gotten used to it?); in the second, that instanceof should diverge from casting. Being able to interpret a pattern match by asking ?what would casting do? is a very powerful technique. Undermining that to avoid a little bit of discomfort would be a huge mistake. I get how these feel like we are ?helping? users by protecting them from foreseeable mistakes. But they are also not helping, by making the language more complicated, arbitrary, and asymmetric (and less expressive). Both paths offer the chance for confusion, but if we choose arbitrary complexity, the confusion is endemic and permanent, whereas if we choose simplicity and uniformity, the confusion eventually recedes into the past. From brian.goetz at oracle.com Wed Feb 5 07:03:29 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 5 Feb 2025 07:03:29 +0000 Subject: Someone is confused by pattern matching (was: Pattern matching on primitive types mxied with instanceof is a footgun) In-Reply-To: <47003A5B-BE9B-4BCD-8F6F-D47045945829@oracle.com> References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> <52763757.93823347.1738709062552.JavaMail.zimbra@univ-eiffel.fr> <47003A5B-BE9B-4BCD-8F6F-D47045945829@oracle.com> Message-ID: <1C96FF56-6E96-432B-8320-D6D31682F1E1@oracle.com> One last comment on this topic: if we didn?t define primitive patterns this way, you would probably not like how constant patterns would work (or, alternately, would be inclined to define new asymmetric rules to help smooth out the gaps.) > On Feb 5, 2025, at 7:55 AM, Brian Goetz wrote: > > Let me address Tagir?s points: > >> On Feb 4, 2025, at 5:00 PM, Tagir Valeev wrote: >> >> Well, I would say that Remi has a point. This is a silent mistake that can be made. > > Agree, the construct can be used incorrectly; in this case the user thought something different from what was going to happen. It is not clear what they thought was going to happen, though; perhaps they mistakenly thought that the coordinates were ints, or perhaps they mistakenly thought that the floats would be lossily converted to ints, as would happen with an assignment or blind cast. If we don?t know what mistake they were making, it?s hard to correct for that (and even harder to correct for both.) > >> You don't see the declaration, as it's in another file so you may forget about original types and assume that they are ints. > > Yes, we discussed this a lot when we did record patterns. But I must point out here: this has absolutely zero to do with primitive patterns. It just so happened that in this example, primitives were used, but one could make the same mistake with a Box and a nested `String` pattern. > >> The code compiles and doesn't even throw an exception, it just works incorrectly. > > Here is where I disagree! It does work correctly! It asks whether the coordinates can be safely converted to integers, and only proceeds if that is the case. And that is a totally reasonable and useful question to ask! It is just that this is not what the user *thought* was going to happen (and, see above, we?re not even sure which mistake the user made). But what the user thought here is only one reasonable way to interpret what should happen. > > You could argue that this syntax is too ?terse?, and this is the source of the problem; we could have specified nesting to require a claim of totality or partiality: > > case Box(partial String s): > case Box(total Object o): > > But I don?t think anyone would have thanked us for that explicitness. (And if the markers were optional, the mistake could still happen.) > >> It would be justified if such code pattern (converting from double to int only when double fits the int) was common, so conditional narrowing could be useful in many other places. But the fact is that it's highly uncommon. Nobody does this. Many other pattern matching features are nice. E.g., I often see the code which can be migrated to pattern switch (we are still on Java 17) and I really want to use it. However, I never see the code which can be migrated to a narrowing primitive pattern. >> >> I don't agree that we should drop primitive patterns completely, but we may reconsider floating point <-> integral conversions and disable them in patterns for a while (enabling them back later will be always possible). > > > Both of these arguments are dangerous arguments; they argue to introduce arbitrary asymmetries in how it works, just to match our guesses about ?what users think.? In the first case, you?re saying that we should forever treat primitives differently from objects (because they work differently today and we have gotten used to it?); in the second, that instanceof should diverge from casting. Being able to interpret a pattern match by asking ?what would casting do? is a very powerful technique. Undermining that to avoid a little bit of discomfort would be a huge mistake. > > I get how these feel like we are ?helping? users by protecting them from foreseeable mistakes. But they are also not helping, by making the language more complicated, arbitrary, and asymmetric (and less expressive). Both paths offer the chance for confusion, but if we choose arbitrary complexity, the confusion is endemic and permanent, whereas if we choose simplicity and uniformity, the confusion eventually recedes into the past. > > From kevinb9n at gmail.com Wed Feb 5 07:16:15 2025 From: kevinb9n at gmail.com (Kevin Bourrillion) Date: Tue, 4 Feb 2025 23:16:15 -0800 Subject: Pattern matching on primitive types mxied with instanceof is a footgun In-Reply-To: References: <716314936.92322909.1738665178934.JavaMail.zimbra@univ-eiffel.fr> <4C5077B7-5C92-4995-9AE6-E5D91664F06B@oracle.com> <52763757.93823347.1738709062552.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Yes, Maurizio raised that at the end of his message. I think this particular example is constructed to preclude that remedy, as it happens to not be an unconditional pattern *either way*. On Tue, Feb 4, 2025 at 10:21?PM Victor Nazarov wrote: > Isn't the problem here is that if-statement was used? > > From my understanding the intention of the code was clear: deconstruct > this value without losing any information, but the problem is that we lack > anything in the language to express this. > > What was supposed to be written was: > > let AlienSpaceship(int x, int y) = spaceship; > > The problem is that since we lack let-statement people started to see > if-statement as a direct substitution, but it never was, at least not fully. > -- > Victor Nazarov > > On Tue, 4 Feb 2025, 23:44 , wrote: > >> >> >> ------------------------------ >> >> *From: *"Kevin Bourrillion" >> *To: *"Maurizio Cimadamore" >> *Cc: *"Tagir Valeev" , "Brian Goetz" < >> brian.goetz at oracle.com>, "Remi Forax" , >> "amber-spec-experts" >> *Sent: *Tuesday, February 4, 2025 6:14:53 PM >> *Subject: *Re: Pattern matching on primitive types mxied with instanceof >> is a footgun >> >> On Tue, Feb 4, 2025 at 8:55?AM Maurizio Cimadamore < >> maurizio.cimadamore at oracle.com> wrote: >> >>> This seems consistent. So the question is: what is the "mistake" we're >>> talking about here? The user thinking it was a _unconditional_ match where >>> in reality that's not the case? While in the case of instanceof >>> unconditionality is harder to spot, if this was a switch, the compiler >>> would have immediately asked the user to provide a default? >>> >>> It seems to me that the reasoning here implies that developers will use >>> "if" + "instanceof" _without an "else" just for the purpose of extract some >>> data, and then complain when the thing doesn't match (because they have no >>> "else", and so their code will fail). It seems like our best weapon in this >>> case is education, rather that introducing arbitrary restrictions and >>> asymmetries in the language? >>> >>> (Or, perhaps, in the future have a way to perform an _unconditional_ >>> extraction without an "if", in which case the compiler will bark if the >>> pattern is not unconditional.) >>> >> In some cases this will be relevant, but in *this *particular example >> we're looping over Spaceship and then checking for AlienSpaceship, so, no >> help. >> >> I think it is fair to acknowledge that this is a weakness of the feature >> design. How to mitigate it? We can try to evangelize always preferring >> `var` for nested type patterns that are expected to be unconditional. >> That's an unfortunate readability trade-off, though. And a static analyzer >> can't know whether you expected it to be unconditional or not, so there >> might not be much it can do to help. >> >> I am not even sure what language change could be considered here. Note >> that this problem is not specific to primitive types, it's just that >> primitive types are currently the only ones that support "value conversion" >> so we're encountering this issue with them first. Post-Valhalla, other >> types might support value conversion too. >> >> >> For me it's more about the conversion being implicit vs explicit. >> Here, we have an implicit conversion while the conversion does not always >> succeed. >> >> I believe such conversions, the one that may not always succeed, should >> be explicit not implicit. >> >> regards, >> R?mi >> >> @Brian, i'm more worry about a TA with more than 10 years of experience >> having trouble to find a bug in a student project written in Java. >> @Tagir, i'm not sure usin floating point values is the issue here, you >> can have the same kind of bug between a character and an int. >> >> >> >> >> On 04/02/2025 16:00, Tagir Valeev wrote: >>> >>> Hello! >>> >>> Well, I would say that Remi has a point. This is a silent mistake that >>> can be made. You don't see the declaration, as it's in another file so you >>> may forget about original types and assume that they are ints. The code >>> compiles and doesn't even throw an exception, it just works incorrectly. It >>> would be justified if such code pattern (converting from double to int only >>> when double fits the int) was common, so conditional narrowing could be >>> useful in many other places. But the fact is that it's highly uncommon. >>> Nobody does this. Many other pattern matching features are nice. E.g., I >>> often see the code which can be migrated to pattern switch (we are still on >>> Java 17) and I really want to use it. However, I never see the code which >>> can be migrated to a narrowing primitive pattern. >>> >>> I don't agree that we should drop primitive patterns completely, but we >>> may reconsider floating point <-> integral conversions and disable them in >>> patterns for a while (enabling them back later will be always possible). >>> >>> With best regards, >>> Tagir Valeev >>> >>> On Tue, Feb 4, 2025 at 12:45?PM Brian Goetz >>> wrote: >>> >>>> Wow, that was pretty amazing. You went from ?one student, who was never >>>> taught about how this works, was confused by it? to ? let?s pull the whole >>>> feature ? in one breath. >>>> >>>> > On Feb 4, 2025, at 11:33?AM, Remi Forax wrote: >>>> > >>>> > Last week, >>>> > one of the TA for the course "OOP using Java" was grading student >>>> projects, >>>> > the subject of the project can be summarize to "you are alone in >>>> space and angry aliens want you to die". >>>> > >>>> > One of the project had a weird bug when displaying aliens. >>>> > Spoiling the result of bug hunting, this is due to students using the >>>> pattern matching on primitive without them realizing it. >>>> > >>>> > Here is a reproducer of the bug: >>>> > >>>> > // in AlienSpaceship.java >>>> > record AlienSpaceship(double x, double y) implements Spaceship { >>>> > ... >>>> > } >>>> > >>>> > ... >>>> > >>>> > // in a method in another class >>>> > ... >>>> > for(Spaceship spacehip : ...) { >>>> > ... >>>> > if (spaceship instanceof AlienSpaceship(int x, int y) { >>>> > // display the alien space ship at (x, y) >>>> > } >>>> > ... >>>> > } >>>> > >>>> > The TA said she was about to give up when she found the issue and >>>> that the Java spec should not allow such pattern. >>>> > I agree with here, pattern matching on primitive types is not a >>>> feature people ask for and mixed with instanceof it's a footgun. >>>> > >>>> > This feature can be re-introduced later using method patterns and it >>>> will be easier to understand the code, >>>> > by example with an hyphotethical method Double.asInt >>>> > >>>> > if (spaceship instanceof AlienSpaceship(Double.asInt(int x), >>>> Double.asInt(int y)) { >>>> > ... >>>> > >>>> > regards, >>>> > R?mi >>>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: