Judging by the hot disputes about
null it should be some kind of the problem, but I have to admit I don’t see any. A lot of people complain about getting
NullPointerException (and alike) as a bad thing — for me it is great. It is the mechanism that stops my program and tells me “listen, the flow of your program is incorrect, I prevented bad things to happen, sit down and fix it”. I am grateful for that because I didn’t add any extra line to my program and yet the runtime keeps me safe.
null values are very useful if you start to treat them as normal citizens among your data, same way as you treat zeros when doing computations.
a = b + c;
Are you sweating because “
b” could be zero?
Some languages try to cover
null “problem” by introducing wrapper class for reference/pointer types (for example Scala with its
Option ¹). However what kind of progress here is made with actually renaming
None? I don’t see any ².
Since C# and extension methods I see things differently — to such extent that I started writing extensions instead of regular methods just to allow
null on the caller side (to this day I remember pride of C++ which guarantees “
this” cannot be
In many cases you have to deal manually with
null, period, but in many, especially when the job is related to collections,
null comes naturally. Consider such task — having HTML node extract first “
<p>” node from its children, and then extract all “
<span>” nodes from its children. If you use XPath query you have one sequence of selectors. How come in classic programming you have to add so many guards against
null? Why not solve this without fear of
var spans = ((node??emptyNode) .Children .Where(it => it.Name=="p") .FirstOrDefault()??emptyNode) .Children .Where(it => it.Name=="span");
The only problem, or rather annoyance, is C# — not
Kotlin addresses the issue directly but misses the point — instead of introducing
coalesce operator it allows subsequent call/access to fail (Kotlin “returns”
var children = node?.Children;
null, the variable ”
children” will be
null as well (Fantom and Groovy also took this approach). I am not saying
coalesce is superior in all cases, but adding a feature which moves you from
null domain into the same
null domain does not look like a solution to me.
Skila will use selective Null Object pattern ³ with short
coalesce operator. For every type you can define a constant
null object for coalescing. And then…
var spans = node->Children .Where(it => it.Name=="p") .FirstOrDefault()->Children .Where(it => it.Name=="span");
spans” won’t be null! Arrow operator (“
->”) is hidden
coalesce call. Because Skila is statically typed checked, it verifies at compile time whether you can use the power of coalescing (it checks if the
null object is defined). And it does the right thing — it moves you from
null domain into not-
This is probably not a complete blueprint — practice will be the best judge — but even upon completion it won’t be a magical wand. If you work on types that are collections, adding
coalesce is like adding a grease into the gears, in other cases you should rely on old “
if”, and for the rest — NPE comes to the rescue.
¹ I say ”yes” to Option, but not instead of null pointers, but as addition to them.
² Why Scala’s “Option” and Haskell’s “Maybe” types won’t save you from null (good read, but the example with
Dictionary is weak).
³ There might a be a little confusion what the true “Null Object” pattern is, so let’s say Kotlin, Fantom, Groovy use thin
null object (no body, everything falls into
nulls), while Skila will use fat objects, with real body defined by user. This will allow to transform
null collections into empty ones.