C# 8.0 introduced non-nullable reference types. I use them because it is considered best practice. I first encountered them in Kotlin. But I’m not a huge fan because they:
- have a cascading effect on interfaces and code
- are often not very helpful
On the first problem, there are cases where things might be null, so you have to keep adding ? and ! and using the smart cast operator etc.
The simple introduction of a late initializer keyword would be helpful as seen in Dart and Kotlin. It basically tells the compiler, this is okay, trust me the programmer, I’ll initialize it in good time.
For example, if C# had Kotlin’s lateinit keyword:
lateinit private IConnectionManager _manager;
All is not lost, there is this tip:
private IConnectionManager _manager = null!;
Mostly, these issues aren’t a big deal.
As to the second point. If you are disciplined, code defensively, and make good use of guard classes, null exceptions are not that hard to avoid. C# avoids a lot of the problems in Java.
I typically use two guard classes in my code:
- Expect – always executes
- Assume – only runs in debug
This distinction allows me to liberally test assumptions knowing they won’t have a runtime hit. Typically public facing methods will use Expect, whilst private methods more often use Assume.
Static analysis tools like Resharper also go along way to helping the developer.
The non-null reference types feature doesn’t help in dynamic situations – that’s where these bugs are really hard to track down. For example, you kick off a new thread in Android, and pass it a reference to the current Activity. The user rotates the screen and the Activity is destroyed and recreated. The thread finishes and calls back the destroyed thread. Anything dynamic, initializing at runtime, always has to be handled by the developer. These are the harder issues to manage.
Lastly, only in simple situations do you check arguments for non-null only. You probably don’t want whitespace for a credit card number, it most likely has to conform to a certain regex pattern etc. So, in most applications, you inevitably end up performing just as many assertions.
I do understand some people love the non-nullable references, all good. I don’t mind them, whatever the team selects is what matters. You don’t really notice them most of the time. Microsoft have done a good job with the implementation.
Future benefits may come from code analyzers and tools, the more metadata the better 🙂
I hope you found the null! tip useful.