The recent proposal to add non-nullable references to C# by Microsoft’s Mads Togersen sparked quite a debate in the .NET community. The reactions were diverse, ranging from praise to preferring status quo.
On Reddit, the proposal elicits many questions about backward compatility. Strilanc feels the proposal wouldn’t allow a smooth transition when turning the flag on:
This proposal needs more work. There's not nearly enough consideration for preserving binary compatibility, source compatibility, and for allowing a gradual transition of existing code.
1. It has an assembly-level switch that changes the meaning of every reference type name to be non-nullable. It changes the meaning of projected-sized chunks of code all at once, requiring massive upfront cost and risk. That is very very bad.
2. The generics part of the proposal needs more fleshing out. The fact that default(T) is no longer allowed in a lot of generic code is not explored at all. How does this issue affect existing code under this proposal, and how is it worked around? How do classes that need it opt into using default(T)?
3. It just lets arrays contain bad initial values? What is the point of putting it in the type system if you're just going to let it be blatantly violated?!
Backward compatibility towards external libraries is also a concern, as Maplemario writes:
But here's the problem. Say I'm using an old library where everything returns T regardless of nullability. Now, the paradigm shift is into assuming that T means non-null T, but I use a function which (validly, when it was written) returns null. Say it's in a rarely tested case of my program. In a perfect world, the documentation outlines this and I read the documentation so I know to null-check, or I remember that it's old code and null-check anyway. In the real world, there's no longer an imperative on me to do null-checking because "T means non-null T", and suddenly my program crashes because I'm dereferencing a null pointer.
Alternatives to the proposal are also actively discussed. A new notation for expressing non-nullability would be preferred by 00Davo:
As much as I'd like the bare type
T
to invariably be non-nullable for any reference, so onlyT?
can ever hold null, it would be a nightmare for backwards compatibility. It'd be a lot less fragile to introduce a new, explicitly non-nullable reference notation -T!
perhaps?
For others, implementing the proposal would be too problematic. Number127 suggests static analysis as an alternate approach:
Sadly, there are too many compatibility issues to introduce non-nullable reference types in a graceful way at this point. I think the most promising approach is static analysis to see what guarantees can be made about a reference while maintaining the current type system.
Static analysis is also discussed on GitHub. Paulo Morgado goes further, stating the current proposal is already disguised static analysis:
If I understand it correctly, this is nothing more than a method contract on steroids. There are no guarantees made by the compiler and less by the runtime. The compiler just does dataflow analysis on variables declared to be nullable.
On another topic, Tomas Petricek points out that other CLR languages like F# have to be considered in the proposal:
Can the proposal be clarified on how are the nullability annotations going to be stored at the CLR level? (I suppose these have no runtime meaning and they would just produce a .NET attribute or some other sort of metadata?)
It would be nice if some future version of the F# compiler could read and understand these and offer some sort of "strict" mode where nullable types are automatically exposed as
option<'T>
(or something along those lines).
The debate on non-nullable references isn’t new, as the question arose several times in the past years. As former Microsoft’s principal developer Eric Lippert states, retrofitting non-nullable references in a 15 years old language is a huge undertaking.