Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Nullable Value Types and the Null-State Machine

โญโญ intermediateโณ 15 min read๐Ÿ“ Lesson 87 of 265

int? vs int, HasValue/GetValueOrDefault, nullable reference type annotations, and making the compiler's warnings into design.

Nullable value types: absence you can see

A value type cannot be null โ€” unless you wrap it: int? is Nullable<int>, a struct holding a bool HasValue plus a T Value.

int? found = list.Find(x => x > 10);   // 0 would be a lie; null means "none"
if (found is int value) Use(value);    // pattern test + unwrap in one step
int fallback = found ?? -1;            // GetValueOrDefault-style default

int? lifts operators: null + 5 is null (not an exception). Comparisons with null are false โ€” null < 5 is false, not true.

Nullable reference types: promises the compiler checks

Since C# 8, reference types are non-nullable by default under NRT. The compiler tracks null-state and warns:

  • string? โ€” "may be null"; you must check before use.
  • string โ€” "expected non-null"; assigning null warns.
  • string? name = Fetch(); var len = name.Length; โ€” warning: possible null.
  • After if (name != null) the compiler knows it is safe โ€” flow analysis.
  • ! (null-forgiving) says "trust me" โ€” a last resort, not a tool.

Two honest tools when null is a legitimate answer:

string? found = dict.GetValueOrDefault(key);        // null is real absence
string  found2 = dict.GetValueOrDefault(key, "");   // or a default

And one dishonest one to avoid: initializing fields with = null! to silence the compiler creates a lie that explodes later.

The nullable machinery in API design

TryX patterns (like Beginner's int.TryParse) return bool + out value; nullable returns let you express "no result" directly:

public static int? ParseAge(string input) =>
    int.TryParse(input, out int age) && age >= 0 ? age : null;

Callers then use ??, is int v, or if (v is not null) โ€” null becomes a visible, checkable part of the contract instead of an ambush.

Check your understanding

  • What is (int?)null == null? (True โ€” lifted equality.)
  • string s = null; under NRT โ€” warning or error? (Warning; still compiles.)
  • Why prefer int? over a magic -1 sentinel? (Sentinels collide with real data.)