Answer
Overview
Sound null safety is Dart's guarantee that non-nullable types can NEVER contain null -- enforced at compile time, not just runtime. It was introduced in Dart 2.12 (stable) and is enabled by default in all modern Flutter/Dart projects.
What 'Sound' Means
Without null safety (before Dart 2.12):
dart// Old Dart -- any variable could be null, no compile-time check String name = null; // Allowed -- crashed at runtime name.length; // NullPointerException at RUNTIME
With SOUND null safety:
dart// Modern Dart -- null safety is SOUND (complete, no exceptions) String name = null; // COMPILE ERROR -- caught before running! String? name = null; // OK -- explicitly declared nullable // Compiler PROVES name is non-null here -- no runtime check needed if (name != null) { print(name.length); // Safe -- compiler promoted to String (non-null) }
Non-nullable vs Nullable
dart// Non-nullable (default) -- guaranteed to never be null String name = 'Alice'; // Never null int age = 28; // Never null List<User> users = []; // Never null // Nullable -- can hold null (add ?) String? email = null; // Can be null int? score = null; // Can be null User? currentUser = null; // Can be null
Working with Nullable Types
dartString? getEmail(int userId) { // May return null return userId == 1 ? 'alice@example.com' : null; } void process() { final email = getEmail(1); // Option 1: null check (compiler promotion) if (email != null) { print(email.length); // No ! needed -- compiler knows it's String here } // Option 2: null coalescing final display = email ?? 'No email'; // Option 3: null-aware access print(email?.toUpperCase()); // null if email is null // Option 4: assert non-null (dangerous -- throws if null) print(email!.length); // Throws if null }
late -- Deferred Non-nullable Initialization
dartclass UserProfile { late String name; // Non-nullable but initialized later late final String id; // Non-nullable final -- set once, later void init(String userId) { name = 'Alice'; // Must be set before use id = userId; // Can only set once (final) } } // If accessed before init -- LateInitializationError (runtime)
Why 'Sound' Matters
textUnsound null safety -- can have runtime null errors despite type annotations Sound null safety -- IMPOSSIBLE to get a null error on a non-nullable type Dart's is SOUND because: 1. All code (including packages) must be null-safe 2. No hidden nullable backdoors 3. Compiler proves null safety at every point
Benefits
| Benefit | Description |
|---|---|
| No NullPointerException | Non-nullable types guaranteed safe |
| Better optimization | Compiler skips null checks in generated code |
| Self-documenting | text text |
| IDE support | Autocomplete knows what can be null |
Summary: Sound null safety means Dart's type system mathematically guarantees non-nullable variables can never be null -- there are no escape hatches. This eliminates an entire class of runtime crashes.