Nullable reference types in C#, a digression

In this series so far:

  1. Some requirements for null-aware types in C#
  2. A basic design
  3. (This article) A wee digression
  4. (Next time) How the design affects generic types
  5. (Probably) Compatibility
  6. (Probably) The Future

In this article we’ll digress about default values…

Note: this post will not make much sense without reading the preceding ones. (And if you’re not a computer scientist or programmer, or don’t care about C# and .NET, it won’t make much sense in any case.)

Default values

In C#, value types have default values. For example, the default value of int is 0; the default value of bool is false, the default value of double is 0.0D and the default value of DateTime is midnight, 1 Jan, 1 CE.

As defined previously, Implicitly-nullable reference types also have a default value: null.

Explicitly-nullable types also have a default value of null.

Non-nullable reference types, like string! or Stream! or Font! do not have default values. In general, there’s no way around this. However, some (not all) reference types could have reasonable defaults. For example, the default value for a string would reasonably be ‘string.Empty’. Default values make sense where the type is an immutable value type.

So (I’m just putting it out there), we could allow the following syntax to declare a default value for non-nullable reference types where it makes sense:

namespace System {
   public sealed class String {
      // You can only declare a default value for your own class:
      public static readonly default Empty = "";

That way, this would be legal C#:

var s = default(string!); // s == ""

In addition, this property…

public string! Name { get; set; }

…defaults to the empty string, rather than throwing a FieldUnassignedException if it’s accessed before it’s assigned.

The default value must be declare in the class in question, must be ‘static readonly’ and there must not be a default declared in a base class. (Defaults may be resolved at compile time or at runtime, so this rule keeps things simple and consistent. However, the rule is possible to subvert it if the base class and derived class are compiled separately.)

It is a small feature, but the primitive type ‘string!’ now behaves much more like other primitive types, int, bool and double. In addition, immutable value types can be declared as structs or classes, and be treated consistently by client code.

These ‘default values’ would carry through everywhere that a FieldUnassignedException would otherwise be thrown or that a ‘default(T)’ expression is used:

  • the array string![10] would initially ‘contain’ 10 empty strings
  • instance variables of type string! would be initialised to empty strings
  • default(string!) always means ‘string.Empty’.

The default would be looked up every time a possibly-unassigned variable is accessed. (So if you create an array ‘string![1000000]’, the runtime does not immediately initialise it with a million empty strings.)


That was just a wee bonus feature.

We’ll get back on track by looking at null-aware generic type code next.

One thought on “Nullable reference types in C#, a digression

  1. Pingback: Nullable reference types in C#, generics | Andrew’s Mental Dribbling

Leave a Reply

Your email address will not be published. Required fields are marked *