Lesson 25 min

Deep Dive: Null Safety

00:00 / 00:00

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:

dart
String 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

dart
String? 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:

dart
class 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:

dart
String? 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."

WhatsApp