Skip to content
Ian Griffiths By Ian Griffiths Technical Fellow I
C# 8.0 nullable references: non-nullable is the new default

The most ambitious new feature in C# 8.0 goes by the name of nullable references. (For information on all the new features, you could always consult my book, Programming C# 8.0, from O'Reilly.)

The aim of this new feature is to mitigate what computer scientist Tony Hoare described as his "billion dollar mistake." C#'s null keyword (like its equivalents in many other languages) can trace its roots back to Algol W, a programming language that Hoare helped design.

In this early language (it appeared in 1966) variables that refer to instances of some particular type can be set to a special value indicating that they do not refer to anything right now, a feature that has been extremely widely copied, and which many (including Tony Hoare) now think has been an extremely costly source of programming errors ever since.

What's wrong with nullability? In a world where any reference may be null, you need to take that into account anywhere your code uses a reference, or you risk a runtime failure.

The Introduction to Rx.NET (v6.1) 3rd Edition (2025) Book, by Ian Griffiths & Lee Campbell, is now available to download for FREE.

Sometimes this won't be too onerous: if you initialize a variable with a new expression at the point where you declare it, you can know that it's not null.

But even in such a simple example there's still some cognitive load: prior to C# 8, the compiler couldn't tell you if you do anything that might change it to null. But as soon as you start connecting pieces of code together, this becomes much hard: is this property I'm reading likely to return null? Am I allowed to pass null into that method? Under what circumstances can I be confident that this method I'm calling will set this out argument to something other than null? And even remembering to check isn't the whole story: sometimes it's not even clear what you should do in the face of a null.

Numeric types don't have this problem in C#: if you write a function that takes some numbers as input and produces a number as a result, you don't have to wonder whether the values passed in are really numbers, and whether they might not in fact be nothing.

If you call such a function you don't have to wonder whether it might return nothing instead of returning a number.

Not unless you really need that as an option, in which case you can declare parameters or results of type int? to indicate that on this particular occasion, you do actually want it to be possible to pass or return no value at all. So for numeric types, and more generally, value types, nullability has always been something you got only if you chose to opt into it.

But for reference types, prior to C# 8.0, not only was nullability the default, you couldn't even switch it off.

In fact, for reasons of backwards compatibility, nullability remains the default even for C# 8.0, because the new language features in this area are disabled until you explicitly ask for them.

Programming C# 12 Book, by Ian Griffiths, published by O'Reilly Media, is now available to buy.

However, once you turn on this new feature, it all changes. The simplest way to enable it is to add <Nullable>enable</Nullable> inside a <PropertyGroup> element in your .csproj file. (As I'll be discussing in later posts in this series, more fine-grained control is possible.

If you really need to, it's possible to configure nullable behaviour line by line. However, in our recent work to switch this feature on in all of our open source projects, we've found that enabling it one project at a time has been manageable so far.)

With C# 8.0's nullable reference features fully enabled, the default changes: all references are presumed to be non-nullable unless you say so, just like with value types. (The syntax is even the same: just as you would write int? if you really want a numeric value to be optional, you now write string? to indicate that you want either a reference to a string or null.)

This is a pretty significant change, and it's the main reason this new feature is off by default.

Microsoft could have designed this language feature differently: they could have had references remain nullable by default, and introduced a new syntax for indicating that you want non-nullabilty.

This might have lowered the bar to adoption, but it would have been the wrong decision in the long run, because in practice, most references in most C# code are intended never to be null. (This has certainly been endjin's experience: as we have enabled nullability in our projects, the cases where we add a ? to revert to the old "null allowed" behaviour are very much in the minority.)

Nullability is the exception, not the rule, and that's why, when you enable this new language feature, non-nullabilty is the new default.

This is even reflected in the feature's name, "nullable references." That's a curious name, given that references have been nullable since C# 1.0. But they chose it to emphasize the fact that nullability is now something you get only if you ask for it.

FAQs

What is Tony Hoare's 'billion dollar mistake' and how does C# 8.0 address it? Tony Hoare's billion dollar mistake refers to the invention of null references in Algol W, which he helped design in 1966. This feature has been widely copied and is considered an extremely costly source of programming errors. C# 8.0 addresses this with nullable references, which changes the default so that all references are presumed non-nullable unless you explicitly say they may be null.
How do you enable nullable reference types in a C# project? The simplest way to enable nullable reference types is to add enable inside a element in your .csproj file. More fine-grained control is also possible, allowing you to configure nullable behaviour line by line if needed.
Why did Microsoft make non-nullable the default when enabling nullable references? Microsoft chose non-nullable as the default because in practice, most references in most C# code are intended never to be null. Nullability is the exception, not the rule. Making nullable the default would have lowered the bar to adoption, but would have been the wrong decision in the long run.
What is the syntax for declaring a nullable reference type in C# 8.0? Just like with value types where you write int? to make a nullable integer, you now write string? to indicate that you want either a reference to a string or null. Without the question mark, the type is presumed to be non-nullable.
Why is the feature called 'nullable references' when references have always been nullable in C#? The name emphasizes that nullability is now something you get only if you ask for it. With the feature enabled, non-nullability is the new default, so the name highlights that you must explicitly opt in to nullable behaviour, reversing the historical norm.

Ian Griffiths

Technical Fellow I

Ian Griffiths

Ian has worked across an extraordinary breadth of computing - from embedded real-time systems and broadcast television to medical imaging and cloud-scale architectures. As Technical Fellow at endjin, he brings this deep cross-domain experience to bear on the hardest technical problems.

A 17-time Microsoft MVP in Developer Technologies, Ian is the author of O'Reilly's Programming C# 12.0 and one of the foremost authorities on the C# language and high-performance .NET development. He's a maintainer of Reactive Extensions for .NET, Reaqtor, and endjin's 50+ open source projects.

Ian has created Pluralsight courses on WPF fundamentals, WPF advanced topics, WPF v4, and the TPL, and has given over 20 talks at conferences worldwide. Technology brings him joy.