The difference between this approach and the approach C# took when they implemented this a few years ago is intereting. With C#, you enable nullability in a project, and every variable is declared as non-null unless you explicitly mark it as nullable (or use compiler directives to disable nullability for a block of code). With this proposal, all existing variables will be effectively nullable, explicitly nullable, or explicitly non-nullable.<p>Kotlin, another JVM language like Java, also follows the C# approach, assuming everything is non-null unless explicitly marked as being non-null, except Kotlin doesn't have backwards compatibility to worry about. Kotlin also offers a special `lateinit var` declaration for leaving a non-nullable type unassigned until initialization in another method, throwing a special exception on uninitialized access, which is an interesting workaround for some code patterns that this approach doesn't seem to cover.<p>I wonder why the choice to offer three options was made. Why not keep the non-annotated variables as nullable and make annotated variables explicitly non-null instead? I can't think of a reason why you would want to declare something as nullable when not declaring anything automatically makes the type nullable anyway.<p>I think I like C#'s approach better, although this has the benefit of being usable in a legacy code base without having to solve any of the nullability issues. Then again, the C# approach does immediately highlight nullability issues in a code base, whereas this proposal hides them the same way they've always been hidden.<p>Additionally, I find this strange:<p>> One method may override another even if the nullness of their parameters and returns do not match.<p>This feels like a footgun for when a developer overrides/implements some kind of callback and returns null where the overridden method specifies non-null return values.