Fwd: Null-Restricted and Nullable Types concern

Caleb Cushing caleb.cushing at gmail.com
Fri Nov 15 16:16:00 UTC 2024


> It is not a goal to automatically re-interpret existing code—use of these features should be optional and explicitly opted in to (future work will explore mechanisms to request a bulk opt-in without needing to change individual types)

Before anything makes it into the JDK I'd like to see the plan for
this, especially since I do not believe such a feature should be
released unless it has been applied to the entirety of the JDK.
Without this the adoption will be almost as slow as JPMS (an aside on
that I'd like progressive enforcement there so it could be possible to
get there).

Not to speak for anyone other than myself, the community seems to be
leaning towards the conversion where non null is the default, and
using marker annotations on packages,classes,modules. This or
something like this to speed conversion would be appreciated. maybe
the following (Evil tangent: let this only exist on module, I'd like
to get modules actually moving, in a different email it'd be nice if
jars without at least an automatic module would start failing to load)

module org.example! {}  // or ?
package org.example.something!; // or ?

could be used for speedy defaults on otherwise unmarked code. Some
have taken to separating API and Fields though.

How do these behave? given the following interface, static
implementations (meaning they aren't doing real loads from an external
database), that Stream::map arguments are marked "?" as nullable and
use

interface MyRepository {
    Stream<Foo?>! findFoos();
}

class Foo {}

given

class MyRepositoryValueNeedsNullCheck implements MyRepository {
    Stream<Foo?>! findFoos() {
        return Stream.of(new Foo(), null);
    }
}

class MyRepositoryValueDoesNotNeedNullCheck implements MyRepository {
    Stream<Foo?>! findFoos() {
        return Stream.of(new Foo());
    }
}

when MyRepositoryValueNeedsNullCheck
findFoos().filter(Objects::nonNull).map( foo -> foo.toString())

when MyRepositoryValueDoesNotNeedNullCheck
findFoos().map( foo -> foo.toString())

will the above be considered "ok" since neither of them would actually
create a runtime error? they should be considered ok in my opinion.

class MyRepositoryValueNeedsNullCheck implements MyRepository {
    Stream<Foo?>! findFoos() {
        return /// do something with a database or something that
cannot be known until runtime
    }
}
when MyRepositoryValueNeedsNullCheck
findFoos().filter(Objects::nonNull).map( foo -> foo.toString())
findFoos().map( foo -> foo.toString())

does the return on findFoos() do an implicit runtime check for the
Stream throwing some good NPE error? will the map without the filter
result in a compile time NPE?

class MyRepositoryValueNeedsNullCheck implements MyRepository {
    Stream<Foo!>? findFoos() {
        return null;
    }
}

is this valid? I have a valid use case for what's more or less the
inverse (where the interface is nullable, but the implementation is
not)

Will we be getting a way to assert variables with inferred types?

`var! foo = null` (tangent: can we reopen mutability on var here?
meaning val! foo or const! foo, that thing I foolishly voted
against... and was wrong, it should exist (I hadn't used a language
that had it yet, maybe I wasn't the only one), I don't like const
because I see that as a static final)

given

Foo! foo;
foo = new Foo();

valid so long as it's assigned before use?

is partial markup really valid at compile time?

interface MyRepository {
    Stream<Foo?> findFoos();
}

I find the examples using this, but then Stream is nullable? it feels
like if you define any nullability on a given type then the whole type
should be fully marked up.

In all of these stream examples, the concept in checker framework is
@PolyNull, will there be a way of writing functional interfaces that
defines that the implementers can use them in a PolyNull fashion?
meaning the null check necessity can't be known until usage is
defined?

Will the compiler strip if null checks out of the bytecode if it
determines they are no longer necessary? probably not necessary to
define in the jep.
-- 
Caleb Cushing

Appointments https://calendly.com/caleb-cushing
https://xenoterracide.com


More information about the valhalla-dev mailing list