Now, one can argue that this is just smoke and mirrors with type erasure and it is but you can already put a Date into a List<Point> if you're so inclined because the JVM doesn't know the difference, hence type erasure. So this is no different.
I'm no JVM expert but from reading the article it seems like the chosen solution for value classes is to treat them all as a single L-type in the JVM where each primitive type is its own L-type. If I read the correctly, it means that if you have a Point value class then on the JVM level you'll be able to stuff any value class into there if you're so incline, just like with List<Point>.
Obviously we need to be concerned with fuzzing (moreso in C++) but here really we're just trying to have sensible defaults that aren't guaranteed because we can't design the language how we want from the ground up without making a new language.
Oh and there is a prosopal for this [2]. Personally, I prefer the Hack version.
And that's a massive problem that they're planing to solve with specialized generics. The blog post does a pretty high level overview of it, but my understanding of it is the following:
1. They are adding a new bytecode class flag for value classes.
2. Primitive wrapper classes will become value classes.
3. Parameterized container classes will be flagged with a new bytecode to enable parametric attributes on initialization with additional data of the parameters in the Constant Pool.
4. Initialization of parameterized classes are done with additional metadata of the type argument stored in the Constant Pool.
5. The runtime does monomorphization of the parameterized class.
It doesn't seem too different to what the CLR does, i.e. runtime monomorphization. The difference is that the JVM implementation is backward compatible with older type-erased code, i.e. the restrictions in Java due to type-erasure are exactly the same as before. It's just additional metadata added to allow the JVM to monomorphize the classes.
There's a whole bunch of specification language describing how constants aren't actually constant in specific situations.
I don't know Kotlin but I assume it does the same thing: until the non-nullable field gets initialized, it holds null and violates the type system.
Kotlin still has a hole where you can run code in "init" blocks which are executed sequentially on object construction; in one, you can call a function that is defined after an unmodifiable property, and it will see the uninitiailized value.
Regarding the 0 value choice in Go, I don't agree that this is worse than null. It simply applies a design constraint that is not usually very hard to satisfy - that the 0 value of your type must have well defined semantics.
If you allow a nonnull field to hold null at any point then it's trivial to leak that out and have nonnull variables holding null all over the program, which is obviously something to be avoided.
Maybe you can say that if you read a nonnull field when it's null, that throws an exception. That might have its own knock-on effects since nobody expects reading a field from a valid reference to throw an exception, but it might be the best way.
Of course, as I said, this ship has long sailed for general Java classes. It would be far too big of a breaking change to add such a limitation today. However, we know for sure this could have been done in Java: this is exactly how record and now value classes work: any call that could expose un initialized fields is in fact disallowed.
This is often given as the defensible reason, but it's not even that true. Java 1.5/5 had several "breaking" changes in it regardless including the newly reserved 'enum' and a whole freaking memory model update.
And besides if any of your dependencies updated for all practical purposes you did, too, since you had to use a newer runtime to run their code regardless, it never really made sense to keep using an older javac out of spite
But a huge mistake (IMHO) was not having nullability part of the type system. You can still do this with type erasure.
Anyway, I read your comment as "nullability isn't complex" (paraphrased) but that's not the author's point. What's complex is having a value class and a regular class of every class and you don't necessary know which one you're dealing with at the language level.
C++ is a great example of this. You can create an object ont he stack or the heap and that's really what we're talking about with that proposal. And that's a nightmare. Combined with pointers it meant you never knew if you could free something or not and that ownership had to be passed around with vague comments like "// retains ownership".
Anyway, the whole article is a great tale of how difficult it is to retrofit things later and how difficult it can be to fix mistakes later (eg java.util.Date).