In this series so far:
- Some requirements for null-aware types in C#
- A basic design
- (This article) A wee digression
- (Next time) How the design affects generic types
- (Probably) Compatibility
- (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, 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.)
Summary
That was just a wee bonus feature.
We’ll get back on track by looking at null-aware generic type code next.
Pingback: Nullable reference types in C#, generics | Andrew’s Mental Dribbling