Feedback on Null-Restricted and Nullable Types
Olexandr Rotan
rotanolexandr842 at gmail.com
Thu Sep 12 10:31:42 UTC 2024
I have given a lot of thought to this topic since my last mail here.
Ultimately, what I have concluded on is that even if we try to somehow
infer nullability, the limits of this inference are drawn on the bounds of
the system and non-final fields. Nullability, though, can be inferred for
local variables, and IDEs already are doing a pretty good job in this area,
so I am not sure if this is a job of jdk to reinvent this analysis once
again.
So, the best idea that crossed my mind so far is to, instead of
forbidding compilation by making non-null default, just be as annoying as
possible *for unspecified nullability* (I emphasize that, as I see, problem
is unspecified nullability rather then specified with '?'), by introducing
some warning for any unspecified nullability type, at least at the bounds
of type (i.e. public and arguably package-private members and their
declaration members), but, if i were to decide, for all members of type.
Local variables could have a bit more loose requirements imo, however,
including them into inspection could encourage people to use var keywords
if that was the point for any reason.
I think that this annoyance is acceptable, because, as I see it, ? notation
is essentially union of type and null, while ! is an explicit statement
that this type does not contain null. Hence, warnings about unspecified
nullability is just a warning that you don't give compiler enough
information to validate your code, in some way like unchecked cast and raw
types warnings currently. This kind of soft but steady power could
potentially end us up in a situation when, eventually, there is little to
none code without nullability notation.
Also, as an option, a tool for nullability inference could be included in
jdk as a separate tool instead of part of the compiler. This could smoothen
the steep path developers would have to take o migrate to new java
versions, by sparing them from work to manually add nullability info to
each local variable
On Wed, Sep 11, 2024 at 11:03 AM Remi Forax <forax at univ-mlv.fr> wrote:
>
>
> ------------------------------
>
> *From: *"Brian Goetz" <brian.goetz at oracle.com>
> *To: *"Olexandr Rotan" <rotanolexandr842 at gmail.com>
> *Cc: *"Enrique" <enrique.arizonbenito at gmail.com>, "valhalla-dev" <
> valhalla-dev at openjdk.org>
> *Sent: *Wednesday, September 11, 2024 2:27:53 AM
> *Subject: *Re: Feedback on Null-Restricted and Nullable Types
>
>
>
> On Sep 10, 2024, at 5:43 PM, Olexandr Rotan <rotanolexandr842 at gmail.com>
> wrote:
>
> I would argue that not the syntax around nulls should be hideous, but
> rather non-null should somehow be the default option
>
>
> We’re going to get this suggestion a lot. It is pretty clear that
> “non-null” is a better default interpretation of an otherwise unannotated
> type name than “nullable” is; this results in a lower annotation burden for
> annotating old code, less visual noise for reading fully annotated code, a
> safer default, etc. And if we were designing a language from scratch, it
> would be pretty hard to argue against this.
>
> But as you acknowledge, there are billions of lines of Java code out
> there, and retroactively changing their meaning is a non-starter. People
> will surely suggest things like “what about a compiler flag” (please
> don’t), but that’s just forking the language and pretending we aren’t. And
> all the “obvious” suggestions have one or both of these characteristics.
>
> So, we truly understand how this would be yet another “Java got the
> defaults wrong”. And maybe there is a path — in the
> not-so-immediate-future — to opting into stricter null checking in a way
> that does not feel like a fork. And we’re going to think about that, and if
> we find something that seems acceptable, we’ll consider it. But as James
> says, if you don’t know the right thing to do, then the right thing to do
> right now is to do nothing. So we will not be tackling the “wrong default”
> problem at the same time as we are addressing null restriction. (Besides,
> there’s enough impossible problems in Valhalla that we don’t need to add
> another one onto our plate.)
>
>
> I see non-null by default as a side effect and not as a goal.
> The goal is to simplify the model we expose to users.
> It's clear that the underlying model is a 3 states model (let's pretend
> there is no type variable for a moment), so String, String? and String!.
> The main advantage of saying it's non-null by default is that it simplify
> the user model to a 2 states model, either String or String? so the user
> model is easier to understand.
> Obviously, once the code interacts with methods from the old world, the
> raw Strings are still there lurking but having a local 2 states model is i
> believe still a win.
>
> So the feature is providing a local 2 states user model and the nice side
> effect of that is having non-null by default.
>
> There are drawbacks to the local 2 states user model, on top of my head,
> how to opt-in ? Is making type variables a special case a good idea ?,
> should the bounds of a type variable be non-null too ? Is having no way to
> represent raw nullability not a problem when trying to guide inference ?
> And i'm sure many more.
>
> Rémi
>
>
> , so people will not bother adding anything on top of that unless
> explicitly needed. I'm not really sure if it's achievable with preserving
> source backward compatibility though, given that currently, default is
> unspecified nullability. I think that many people will bother adding ! as
> much as ?, honestly. Most of the production code I have worked with
> didnt even care about returning an unmodifiable view of collection instead
> of the real one or wrapping nullable value in optional in getters and
> hiding no-args constructors in POJO using protected keyword. Honestly, the
> sad truth (in my experience) is the fact that if something is not done by
> default, it will not be done manually in the vast majority of cases, no
> matter how potentially beneficial it is. I would say that best option would
> be to introduce compiler flag that enables non-null by default, and
> eventually, after most users are migrated, make it true by default.
>
> Regarding new null in language. I (unfortunately) spend at least half of
> my working with typescript. To say that this null-undefined fuss is
> terrible is to keep silent. That's just a complete mess. Question mark in
> type stands only for type | undefined, want to accept null - go and do
> var?: type | null - just terrible. Question mark notation in field access
> chains is also so strange: it, contrary to ? in type, accepts both null and
> undefined, and it often leads to confusing situations when you expect one
> of those two, but get another, logic in ?? still executes, and your
> erroneous state passes down through long chain of invocation until it
> finally fails somewhere and good luck debugging it/ Two different nulls is
> just a horrible idea in so many ways.
>
> PS: Nothing bad with nulls by themself. Absence of value is also a value
> in many scenarios
>
> On Tue, Sep 10, 2024 at 8:46 PM Brian Goetz <brian.goetz at oracle.com>
> wrote:
>
>> The following was received on valhalla-spec-comments.
>>
>> Point #1 rests on an assumption that the goal of this feature is to
>> eliminate, or at least strongly discourage, nulls. This is a common
>> assumption — many people are so-called “null haters” — but encouraging or
>> rewarding such biases is not the role of the langauge. Nulls are not
>> intrinsically bad; the problem with nulls is that they are so often
>> unexpected, and so people code as if they would never happen. Reflecting
>> nullity in the type system allows you to reason about when they are
>> expected, and make reasoned choices about where nulls are appropriate or
>> not.
>>
>> You state your position pretty explicitly here:
>>
>> >> The syntax to use null must be "disgusting enough" in order to
>> >> discourage people from using it.
>>
>> I’m not going to criticize your opinions about nulls, but it is also OK
>> to have different opinions about nulls, and it’s not the role of the
>> language to insist that one or the other is the only valid set of feelings
>> about it.
>>
>> Your second point is what we call “inventing a new null”; it is a
>> tempting answer, but is overwhelmingly likely to just make the problem
>> worse, because now there are two ill-behaved states.
>>
>>
>> > On Sep 10, 2024, at 10:46 AM, Enrique <enrique.arizonbenito at gmail.com>
>> wrote:
>> >
>> > REF: https://openjdk.org/jeps/8303099
>> >
>> > Feedback 1:
>> >
>> > Using the syntax "Foo?" for nullables values does not discourage the
>> > use of nulls in code.
>> >
>> > In my experience working with Kotlin, novice (and not so novice)
>> > developers just find themselves comfortable enough adding an extra
>> > character and continue to infest code with nulls.
>> >
>> > The syntax to use null must be "disgusting enough" in order to
>> > discourage people from using it.
>> >
>> > For example something like Foo!!!NullBackwardCompliant!!!. This syntax
>> > is ugly enough to scare people about using it.
>> >
>> >
>> > Feedback 2:
>> > Most people naively tends to use null in next scenarios:
>> >
>> > * A class/record must be initialized, but due to the data flow, some
>> > of its members are not yet known in "present time". They depend on
>> > future input data/processing.
>> > * Some member must not take any value in a given context.
>> >
>> > Ideally the JVM would be extended to support "FUTURE" and "NA" (Not
>> > Apply) values in parallel to null. Any read must throw a
>> > FuturePointerException or NAPointerException.
>> > While the behaviour looks similar to the current null and
>> > NullPointerException, it makes error debugging much easier to
>> > understand:
>> > * A FuturePointerException promptly warns about some race condition:
>> > Some code tried to read a value before some process (maybe another
>> > thread) initialized it.
>> > * A NAPointerException promptly warns about some error in the business
>> > logic. Some code didn't contemplate the NA scenario.
>> >
>> > "catch" blocks will also be able to make much more sensible decisions
>> > (when compared to the pervert NullPointerException).
>> >
>> > Without any JVM extension, a compiler most probably can automate a
>> > similar behavior with a syntax similar to:
>> >
>> > var Foo1 = Future
>> > var Foo2 = NA
>> >
>> > Foo1 and Foo2 are **NOT** nullables.
>> >
>> > Foo2 becomes a constant (It will never change once defined and the
>> > compiler can make many verifications out of the box).
>> >
>> > Foo1 must never be read until a given value is provided (after which
>> > it will probably become constant).
>> >
>> >
>> > My two cents!
>> >
>> > Enrique Arizón Benito
>> > Software Gardener
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-dev/attachments/20240912/c32ee4ca/attachment-0001.htm>
More information about the valhalla-dev
mailing list