From daniel.smith at oracle.com Wed Oct 2 03:43:39 2024 From: daniel.smith at oracle.com (Dan Smith) Date: Wed, 2 Oct 2024 03:43:39 +0000 Subject: EG meeting *canceled*, 2024-10-02 Message-ID: <10220BA3-AC34-4E7D-A76C-120DF8406031@oracle.com> Nothing new for tomorrow, so meeting canceled. Progress report is the same as last time :-) > We're hard at work on the design for nullness features, working through thorny issues with things like generics and flow analysis (which were kept very vague in the current JEP draft). Hoping to converge towards something in the next few weeks that we can put in the JEP. > From forax at univ-mlv.fr Wed Oct 2 07:16:29 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 2 Oct 2024 09:16:29 +0200 (CEST) Subject: Nullability in Java Message-ID: <355265922.23091075.1727853389830.JavaMail.zimbra@univ-eiffel.fr> Hello, i would like a propose a semantics adding a null-analysis to Java. Principles - 1/ the compiler should emit a warning only if a NullPointerException will occur if the value is null - 2/ the syntax should explicitly indicate where a NPE can occur - 3/ the compiler should be smart enough to avoid bothering users when a NPE can not occur (by example: after a "if (a != null)" a should be considered as non-null) Nice to have - while the internal representation is a 3 states (String!, String? and String), it should be cool if users can only denote two states to simplify the action a user can do - the change of the JLS should be confined to a section Proposal: - on field, methods, casts, arrays and type arguments, the null-analysis marker '!' can be used to denote a non-null type. A NPE will be raised - if a null value is stored in such field, array, - if a null value is casted to a non-null type, - if a null value is pass as argument of a method parameter typed with a non-null type Example: class Foo { String! s; String![] array = ...; void m(String! a) {} // NPE void main() { s = aMethodThatReturnsNull(); // NPE array[0] = aMethodThatReturnsNull(); // NPE var o = (String!) aMethodThatReturnsNull(); // NPE m(aMethodThatReturnsNull()); } } - on field, methods, casts, arrays and type arguments, the null-analysis marker'?' can be used to denote a nullable type. - Inside methods, local variable declaration are NOT annotated with nullability marker, the nullability is inferred, so the analysis - can be smarter than the current type-checking, especially the nullability of a local variable can change depending on the control flow - the analysis can be separated from the type checking in the spec (but not in the compiler) - even if the proposed semantics is not non-null by default, a user will not have to annotate a lot of locus, mostly only fields and methods. Example: class Bar { String! aMethodThatCannotReturnsNull() { ... } String? aMethodThatReturnsNull() { return null; } void main() { String s = aMethodThatCannotReturnsNull(); // the type of 's' is inferred as String! String s2 = aMethodThatReturnsNull(); // the type of 's2' is inferred as String? if (s2 != null) { // here the type of s2 is String! } } } - on fields and methods, every type wich is not a ! (a non-null type) is a ? (a nullable type) if there is already a '?' or '!' in the same compilation unit (same file). Having a '?' or '!' somewhere acts as an opt-in to the null-analysis mechanism, it guarantee that - until you opt-in, no warnings can be raised - if you opt-in, the user model has only two denotable kinds of nullability, String! and String?, the latter can written String - A type variable is nullable by default and propagate the nullability information if a user has opt-in to the null-analysis. At declaration site, E is equivalent to E?, which really means E extends Object? Example: class Foo { // a '?' is present so the user as opt-in to E propagating the nullability information void m(E! e) { } // m() can not be called with null void m2(E e) { } // equivalent to void m2(E?) ) - As discussed previously, a field with a non-null type must be initialized in the constructor before the call to the super constructor call. - @SuppressWarnings("null-analysis") allows to suppress any null warnings so even if a user has opt-in to the null analysis it can still incrementally had the null marker later. This also allows add null markers on public methods (on the API) without having any warnings in the implementation. regards, R?mi From brian.goetz at oracle.com Wed Oct 2 12:51:34 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 2 Oct 2024 12:51:34 +0000 Subject: Nullability in Java In-Reply-To: <355265922.23091075.1727853389830.JavaMail.zimbra@univ-eiffel.fr> References: <355265922.23091075.1727853389830.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <98D6E2AD-2920-4C18-BF7B-0E1C5A4C4511@oracle.com> This aligns pretty well with what we?ve been discussing. Your principle (1) is key, because this is what enables adding nullity annotations to be source-compatible, and we want to minimize the friction to adding nullity annotations. This means warnings, not errors, backed up by dynamic checks. From a language perspective, the states `String` and `String?` are semantically identical; the only difference between them is what warnings might be emitted. I don?t see the point of excluding locals (or indeed, any) declarations from being null-markable. (Some are already implicitly null-restricted, such as the throws clause.) Doing so will creates ?gates? that impede the flow of type information, which would undermine your principle (3). > On Oct 2, 2024, at 3:16 AM, Remi Forax wrote: > > Hello, > i would like a propose a semantics adding a null-analysis to Java. > > Principles > - 1/ the compiler should emit a warning only if a NullPointerException will occur if the value is null > - 2/ the syntax should explicitly indicate where a NPE can occur > - 3/ the compiler should be smart enough to avoid bothering users when a NPE can not occur (by example: after a "if (a != null)" a should be considered as non-null) > > Nice to have > - while the internal representation is a 3 states (String!, String? and String), it should be cool if users can only denote two states to simplify the action a user can do > - the change of the JLS should be confined to a section > > Proposal: > - on field, methods, casts, arrays and type arguments, the null-analysis marker '!' can be used to denote a non-null type. > A NPE will be raised > - if a null value is stored in such field, array, > - if a null value is casted to a non-null type, > - if a null value is pass as argument of a method parameter typed with a non-null type > > Example: > class Foo { > String! s; > String![] array = ...; > > void m(String! a) {} // NPE > > void main() { > s = aMethodThatReturnsNull(); // NPE > array[0] = aMethodThatReturnsNull(); // NPE > var o = (String!) aMethodThatReturnsNull(); // NPE > m(aMethodThatReturnsNull()); > } > } > > - on field, methods, casts, arrays and type arguments, the null-analysis marker'?' can be used to denote a nullable type. > > - Inside methods, local variable declaration are NOT annotated with nullability marker, the nullability is inferred, > so the analysis > - can be smarter than the current type-checking, especially the nullability of a local variable can change depending on the control flow > - the analysis can be separated from the type checking in the spec (but not in the compiler) > - even if the proposed semantics is not non-null by default, a user will not have to annotate a lot of locus, mostly only fields and methods. > > Example: > class Bar { > String! aMethodThatCannotReturnsNull() { ... } > String? aMethodThatReturnsNull() { return null; } > > void main() { > String s = aMethodThatCannotReturnsNull(); // the type of 's' is inferred as String! > String s2 = aMethodThatReturnsNull(); // the type of 's2' is inferred as String? > if (s2 != null) { > // here the type of s2 is String! > } > } > } > > - on fields and methods, every type wich is not a ! (a non-null type) is a ? (a nullable type) > if there is already a '?' or '!' in the same compilation unit (same file). > Having a '?' or '!' somewhere acts as an opt-in to the null-analysis mechanism, it guarantee that > - until you opt-in, no warnings can be raised > - if you opt-in, the user model has only two denotable kinds of nullability, String! and String?, the latter can written String > > - A type variable is nullable by default and propagate the nullability information if a user has opt-in to the null-analysis. > At declaration site, E is equivalent to E?, which really means E extends Object? > > Example: > class Foo { // a '?' is present so the user as opt-in to E propagating the nullability information > void m(E! e) { } // m() can not be called with null > void m2(E e) { } // equivalent to void m2(E?) > ) > > - As discussed previously, a field with a non-null type must be initialized in the constructor before the call to the super constructor call. > > - @SuppressWarnings("null-analysis") allows to suppress any null warnings so even if a user has opt-in to the null analysis it can still > incrementally had the null marker later. This also allows add null markers on public methods (on the API) without having any warnings > in the implementation. > > regards, > R?mi > From forax at univ-mlv.fr Wed Oct 2 14:29:53 2024 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Wed, 2 Oct 2024 16:29:53 +0200 (CEST) Subject: Nullability in Java In-Reply-To: <98D6E2AD-2920-4C18-BF7B-0E1C5A4C4511@oracle.com> References: <355265922.23091075.1727853389830.JavaMail.zimbra@univ-eiffel.fr> <98D6E2AD-2920-4C18-BF7B-0E1C5A4C4511@oracle.com> Message-ID: <1415045514.23805363.1727879393455.JavaMail.zimbra@univ-eiffel.fr> ----- Original Message ----- > From: "Brian Goetz" > To: "Remi Forax" > Cc: "valhalla-spec-experts" > Sent: Wednesday, October 2, 2024 2:51:34 PM > Subject: Re: Nullability in Java Hello, > This aligns pretty well with what we?ve been discussing. Your principle (1) is > key, because this is what enables adding nullity annotations to be > source-compatible, and we want to minimize the friction to adding nullity > annotations. This means warnings, not errors, backed up by dynamic checks. > > From a language perspective, the states `String` and `String?` are semantically > identical; the only difference between them is what warnings might be emitted. > > I don?t see the point of excluding locals (or indeed, any) declarations from > being null-markable. (Some are already implicitly null-restricted, such as the > throws clause.) Doing so will creates ?gates? that impede the flow of type > information, which would undermine your principle (3). I don't fully understand what you mean by "gates". The point is to have the type of locals to change their null-marker implicitly. I see two reasons why. 1) If you have a code like: String s = f(); g(s); If 's' has its null-marker computed automatically, the null marker will flow naturally without the user having to update his code each time the API of a dependency is updated to use null-marker. 2) until now, the type of a local variable would never change, we have even introduced the concept of binding to explicitly avoid a local variable to have its type changed. But we also want the nullability part of the type of a local to change dependending on the control flow, so having a way to denote the nullability on a local's type given that it can changed is weird. By example, with class Foo { void m(String! a) { ... } void main() { String? s = ... if (s == null) { // s is know a String! ... } } } Here, declaring that the type of s is a '?' is not true for the lifetime of the variable because the nullability of the type of s can change depending on the control flow. Avoiding to have a way to denote the nullability of the type of a local variable avoid that issue. R?mi > >> On Oct 2, 2024, at 3:16 AM, Remi Forax wrote: >> >> Hello, >> i would like a propose a semantics adding a null-analysis to Java. >> >> Principles >> - 1/ the compiler should emit a warning only if a NullPointerException will >> occur if the value is null >> - 2/ the syntax should explicitly indicate where a NPE can occur >> - 3/ the compiler should be smart enough to avoid bothering users when a NPE can >> not occur (by example: after a "if (a != null)" a should be considered as >> non-null) >> >> Nice to have >> - while the internal representation is a 3 states (String!, String? and String), >> it should be cool if users can only denote two states to simplify the action a >> user can do >> - the change of the JLS should be confined to a section >> >> Proposal: >> - on field, methods, casts, arrays and type arguments, the null-analysis marker >> '!' can be used to denote a non-null type. >> A NPE will be raised >> - if a null value is stored in such field, array, >> - if a null value is casted to a non-null type, >> - if a null value is pass as argument of a method parameter typed with a >> non-null type >> >> Example: >> class Foo { >> String! s; >> String![] array = ...; >> >> void m(String! a) {} // NPE >> >> void main() { >> s = aMethodThatReturnsNull(); // NPE >> array[0] = aMethodThatReturnsNull(); // NPE >> var o = (String!) aMethodThatReturnsNull(); // NPE >> m(aMethodThatReturnsNull()); >> } >> } >> >> - on field, methods, casts, arrays and type arguments, the null-analysis >> marker'?' can be used to denote a nullable type. >> >> - Inside methods, local variable declaration are NOT annotated with nullability >> marker, the nullability is inferred, >> so the analysis >> - can be smarter than the current type-checking, especially the nullability of a >> local variable can change depending on the control flow >> - the analysis can be separated from the type checking in the spec (but not in >> the compiler) >> - even if the proposed semantics is not non-null by default, a user will not >> have to annotate a lot of locus, mostly only fields and methods. >> >> Example: >> class Bar { >> String! aMethodThatCannotReturnsNull() { ... } >> String? aMethodThatReturnsNull() { return null; } >> >> void main() { >> String s = aMethodThatCannotReturnsNull(); // the type of 's' is inferred as >> String! >> String s2 = aMethodThatReturnsNull(); // the type of 's2' is inferred as >> String? >> if (s2 != null) { >> // here the type of s2 is String! >> } >> } >> } >> >> - on fields and methods, every type wich is not a ! (a non-null type) is a ? (a >> nullable type) >> if there is already a '?' or '!' in the same compilation unit (same file). >> Having a '?' or '!' somewhere acts as an opt-in to the null-analysis mechanism, >> it guarantee that >> - until you opt-in, no warnings can be raised >> - if you opt-in, the user model has only two denotable kinds of nullability, >> String! and String?, the latter can written String >> >> - A type variable is nullable by default and propagate the nullability >> information if a user has opt-in to the null-analysis. >> At declaration site, E is equivalent to E?, which really means E extends Object? >> >> Example: >> class Foo { // a '?' is present so the user as opt-in to E propagating the >> nullability information >> void m(E! e) { } // m() can not be called with null >> void m2(E e) { } // equivalent to void m2(E?) >> ) >> >> - As discussed previously, a field with a non-null type must be initialized in >> the constructor before the call to the super constructor call. >> >> - @SuppressWarnings("null-analysis") allows to suppress any null warnings so >> even if a user has opt-in to the null analysis it can still >> incrementally had the null marker later. This also allows add null markers on >> public methods (on the API) without having any warnings >> in the implementation. >> >> regards, >> R?mi From daniel.smith at oracle.com Tue Oct 15 20:30:26 2024 From: daniel.smith at oracle.com (Dan Smith) Date: Tue, 15 Oct 2024 20:30:26 +0000 Subject: EG meeting *canceled*, 2024-10-16 Message-ID: Still working out some nullness details... Let's skip the EG meeting one more time, and I'll plan to have an update to discuss on October 30. From daniel.smith at oracle.com Wed Oct 30 03:59:25 2024 From: daniel.smith at oracle.com (Dan Smith) Date: Wed, 30 Oct 2024 03:59:25 +0000 Subject: Strict field verification Message-ID: <8F7B3D31-0209-4AA4-BB21-7AE17D54CF2E@oracle.com> Here's a draft spec for JEP 401 that adds verification rules to ensure that strict instance fields are assigned to before a constructor calls 'super()': https://cr.openjdk.org/~dlsmith/jep401/jep401-20241030/specs/value-objects-jvms.html Briefly, this change includes: - Enhancing the treatment of verification flags to support new kinds of flags - Defining 'flagFieldUnset' flags for unset strict instance fields - Enhancing StackMapTable to be able to express these flags - Removing the flags in 'putfield' - Ensuring the fields are removed in 'invokespecial' I'd like to go over it at tomorrow's EG meeting. It's fresh, so I wouldn't be surprised if there are a few bugs! Hopefully it covers all the key new concepts. From daniel.smith at oracle.com Wed Oct 30 04:09:45 2024 From: daniel.smith at oracle.com (Dan Smith) Date: Wed, 30 Oct 2024 04:09:45 +0000 Subject: EG meeting, 2024-10-30 Message-ID: <51B91CE2-D016-4C3D-8642-3ECB569DB2CA@oracle.com> EG meeting Wednesday, October 30. We can review the strict field verification spec that I shared. Zoom time: Wednesday, 16:00 UTC (9am PDT, 12pm EDT, 5pm CET) (Note that US is currently on summer time, and Europe is not.)