Look at how Go did it. Any value type has a defined 0 value, and any variable of field of that type is initialized to 0 by default. So any un-initialized non-null able value type field could have the corresponding 0 value.

That's worse than null. Now every object has an invalid state. It works for Go because Go is trying to keep language complexity low. It has no good design principles behind it other than that. Also the zero value of a reference is null so you still haven't answered how a non-nullable reference field would work.

Sorry, I misinterpreted your question to be about non-nullable value classes, not non-nullable classes more generally. For reference variables, it seems that the a priori best approach would have been to generate a compiler error if the field was read before it was written; since this ship has long since sailed with final fields, it seems that the same approach would have to be taken - the "not null able" guarantee only applies after the class is fully initialized, and you can observe it as null during initialization. This is probably not a huge problem, given that initialization code always has to deal with a class breaking its invariants, since they are only established at the end of initialization.

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.