Deep Dive: Null Safety
The Billion Dollar Mistake
Tony Hoare, the inventor of null references, called it his "billion dollar mistake." NullPointerException has crashed more production systems than any other single bug. Dart's null safety system eliminates this entire class of errors at compile time.
Dart's null safety (introduced in Dart 2.12, 2021) is sound — the compiler proves that a non-nullable variable will never be null. This is stronger than Kotlin's or Swift's nullable systems.
Non-Nullable by Default
In Dart, every type is non-nullable by default:
dartString name = 'JavaShark'; // Cannot be null — compiler enforced // name = null; // COMPILE ERROR // To allow null, you must explicitly opt in with '?' String? optionalName = null; // This is fine
The Nullable Type Operators
dartString? maybeNull = fetchName(); // might return null // 1. Null-aware access (?.) int? length = maybeNull?.length; // returns null if maybeNull is null // 2. Null coalescing (??) String display = maybeNull ?? 'Anonymous'; // 3. Null assertion (!) — use with caution! String definitelyNotNull = maybeNull!; // throws if null at runtime // 4. Conditional assignment (??=) maybeNull ??= 'Default Value'; // assigns only if currently null
Late Variables
Sometimes you know a variable will be initialized before use, but the compiler can't prove it:
dartclass UserProfile { // 'late' tells the compiler: "trust me, this will be set before use" late String userName; void initialize(String name) { userName = name; // Must be called before accessing userName } void display() { print(userName); // LateInitializationError if initialize() wasn't called } }
Flow Analysis & Promotion
Dart's null safety includes sophisticated flow analysis. After a null check, the compiler promotes the type:
dartString? value = getValue(); if (value != null) { // Inside this block, 'value' is promoted to String (non-nullable) print(value.length); // No null check needed — compiler knows! } // Pattern matching also promotes: if (value case String s) { print(s.toUpperCase()); // 's' is guaranteed String }
Practical Null Safety Patterns
dart// GOOD: Prefer non-nullable types everywhere possible class Product { final String id; final String name; final double price; const Product({ required this.id, required this.name, required this.price, }); } // Use nullable only when genuinely optional class CartItem { final Product product; final String? discountCode; // Genuinely optional const CartItem(this.product, {this.discountCode}); }
Summary
Null safety transforms Dart from a language where NullPointerException is always lurking into one where null errors are impossible unless you explicitly opt in with ?. Embrace non-nullable types everywhere and treat ? as a meaningful API signal: "this value might be absent."