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 ccherlin at gmail.com Thu Oct 10 16:37:01 2024 From: ccherlin at gmail.com (Clement Cherlin) Date: Thu, 10 Oct 2024 11:37:01 -0500 Subject: Nullability in Java In-Reply-To: <1415045514.23805363.1727879393455.JavaMail.zimbra@univ-eiffel.fr> References: <355265922.23091075.1727853389830.JavaMail.zimbra@univ-eiffel.fr> <98D6E2AD-2920-4C18-BF7B-0E1C5A4C4511@oracle.com> <1415045514.23805363.1727879393455.JavaMail.zimbra@univ-eiffel.fr> Message-ID: On Wed, Oct 2, 2024 at 9:30?AM wrote: > ----- 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 > Hi, The type of a nullable variable does not change even when the nullness of the value it contains is known. If a variable declared as "String? s" contains a value that is known to be non-null at a given execution point, the type of s is still "String?". Consider the following example: String? s = maybeNullString(); if (s != null) { s = null; // legal } Inside the if block the _value_ of s is known to be non-null, but the _type_ of s is still "String?" and not "String!". If the type had changed to "String!", the commented line would be illegal. Now consider another example: void nonNullableStringMethod(String! notNullString) { ... } void main() { String? s = maybeNullString(); if (s != null) { nonNullableStringMethod(s); // legal } nonNullableStringMethod(s); // illegal } The value s holds is known to be non-null inside the if block, so that non-null value is a valid argument to nonNullableStringMethod(). But outside the if block, the value s holds is not known to be non-null, so the value s holds is not a legal argument to nonNullableStringMethod(). This is different than type information. As you mentioned, type information is not control-flow-dependent, requiring casting or pattern matching to change. CharSequence cs1 = "x"; if (cs1 instanceof String) { nonNullableStringMethod(cs1); // illegal } The variable cs1 has type CharSequence, not String, and Java does not use instanceof to perform flow-dependent type inference (it could, but it doesn't). CharSequence cs2 = "x"; if (cs2 instanceof String s) { nonNullableStringMethod(s); // legal } Rebinding declares a new variable with the specified type. Cheers, Clement Cherlin -------------- next part -------------- An HTML attachment was scrubbed... URL: From ccherlin at gmail.com Fri Oct 11 16:46:01 2024 From: ccherlin at gmail.com (Clement Cherlin) Date: Fri, 11 Oct 2024 11:46:01 -0500 Subject: Nullability in Java In-Reply-To: References: <355265922.23091075.1727853389830.JavaMail.zimbra@univ-eiffel.fr> <98D6E2AD-2920-4C18-BF7B-0E1C5A4C4511@oracle.com> <1415045514.23805363.1727879393455.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Hello, I did some more thinking and have clarified my responses. On Wed, Oct 2, 2024 at 9:30?AM wrote: > 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. I don't follow. If I null-marked my code consistently, why would I need to update it when my API dependencies change? On the other hand, if I marked my code inconsistently with my API dependencies, then I probably need to update my code, because my assumptions were incorrect! 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. To put my earlier comments much more succinctly, "nullability" is not the same as "nullness". The nullability of a variable's type is always how it is null-marked. Nullability does not change, regardless of control flow. Nullness does change with control flow. Values of nullable types have different nullness at different points in a program. Declaring static nullability enhances dynamic nullness analysis and helps detect bugs. For that reason, we should allow and encourage null-marking local variables. Cheers, Clement Cherlin -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Fri Oct 11 17:42:54 2024 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Fri, 11 Oct 2024 19:42:54 +0200 (CEST) Subject: Nullability in Java In-Reply-To: References: <355265922.23091075.1727853389830.JavaMail.zimbra@univ-eiffel.fr> <98D6E2AD-2920-4C18-BF7B-0E1C5A4C4511@oracle.com> <1415045514.23805363.1727879393455.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <753004762.34135549.1728668574913.JavaMail.zimbra@univ-eiffel.fr> > From: "Clement Cherlin" > To: "Valhalla Expert Group Observers" , > "Remi Forax" , "Brian Goetz" > Sent: Thursday, October 10, 2024 6:37:01 PM > Subject: Re: Nullability in Java > On Wed, Oct 2, 2024 at 9:30 AM < [ mailto:forax at univ-mlv.fr | forax at univ-mlv.fr > ] > wrote: >> ----- Original Message ----- >>> From: "Brian Goetz" < [ mailto:brian.goetz at oracle.com | brian.goetz at oracle.com ] >> > > >> > To: "Remi Forax" < [ mailto:forax at univ-mlv.fr | forax at univ-mlv.fr ] > >>> Cc: "valhalla-spec-experts" < [ mailto:valhalla-spec-experts at openjdk.java.net | >> > valhalla-spec-experts at openjdk.java.net ] > >> > 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 > Hi, Hello, > The type of a nullable variable does not change even when the nullness of the > value it contains is known. If a variable declared as "String? s" contains a > value that is known to be non-null at a given execution point, the type of s is > still "String?". > Consider the following example: > String? s = maybeNullString(); > if (s != null) { > s = null; // legal > } > Inside the if block the _value_ of s is known to be non-null, but the _type_ of > s is still "String?" and not "String!". If the type had changed to "String!", > the commented line would be illegal. The way I see this is that the type is composed of two types, the one you used when writing and the one used when reading. inside the if, and before assigning null to 's', the type of 's' is (WRITE=String?, READ=String!). Kotlin does something similar for modeling platform types, https://www.youtube.com/watch?v=2IhT8HACc2E regards, R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: 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 ccherlin at gmail.com Tue Oct 15 21:43:03 2024 From: ccherlin at gmail.com (Clement Cherlin) Date: Tue, 15 Oct 2024 16:43:03 -0500 Subject: Nullability in Java In-Reply-To: <753004762.34135549.1728668574913.JavaMail.zimbra@univ-eiffel.fr> References: <355265922.23091075.1727853389830.JavaMail.zimbra@univ-eiffel.fr> <98D6E2AD-2920-4C18-BF7B-0E1C5A4C4511@oracle.com> <1415045514.23805363.1727879393455.JavaMail.zimbra@univ-eiffel.fr> <753004762.34135549.1728668574913.JavaMail.zimbra@univ-eiffel.fr> Message-ID: On Fri, Oct 11, 2024 at 12:42?PM wrote: > > > ------------------------------ > > *From: *"Clement Cherlin" > *To: *"Valhalla Expert Group Observers" < > valhalla-spec-observers at openjdk.org>, "Remi Forax" , > "Brian Goetz" > *Sent: *Thursday, October 10, 2024 6:37:01 PM > *Subject: *Re: Nullability in Java > > On Wed, Oct 2, 2024 at 9:30?AM wrote: > >> ----- 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 >> > > Hi, > > > Hello, > > > The type of a nullable variable does not change even when the nullness of > the value it contains is known. If a variable declared as "String? s" > contains a value that is known to be non-null at a given execution point, > the type of s is still "String?". > > Consider the following example: > > String? s = maybeNullString(); > if (s != null) { > s = null; // legal > } > > Inside the if block the _value_ of s is known to be non-null, but the > _type_ of s is still "String?" and not "String!". If the type had changed > to "String!", the commented line would be illegal. > > > The way I see this is that the type is composed of two types, the one you > used when writing and the one used when reading. > inside the if, and before assigning null to 's', the type of 's' is > (WRITE=String?, READ=String!). > > Kotlin does something similar for modeling platform types, > https://www.youtube.com/watch?v=2IhT8HACc2E > > regards, > R?mi > I suppose I agree to the extent that one could consider "nullness" to be the read type and "nullability" to be the write type, but I don't really think of "nullness" as type information at all. Nullness analysis is more like definite assignment analysis than it is like type analysis. Definite assignment and nullness are flow-dependent. Each node in the control flow graph has both definite assignment and nullness metadata for each variable in scope at that node. Definite assignment and nullness metadata are used to determine whether certain operations, such as reads, writes, and method calls are legal or illegal at each point. It's illegal to read from a variable unless that variable is definitely assigned. Likewise, it is illegal to use a variable in a non-nullable context unless that variable is definitely not null. Neither analysis affects the types of variables. A String? always remains a String?. It doesn't become a String! when itis assigned a non-null value, it becomes a String {DEFINITELY_ASSIGNED,NOT_NULL}. Side note: There are a few major differences. Non-final variables can change their nullness many times in sequence, while definite assignment only occurs once in a given execution path. Definite assignment is an implicit requirement of the language, while nullability marking is explicit. And nullness can change based on nullness tests, not just assignments. Cheers, Clement Cherlin -------------- next part -------------- An HTML attachment was scrubbed... URL: 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.) 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.