Skip to main content
In Dart, null is a built-in literal representing the intentional absence of a value. Architecturally, null is the single, immutable instance of the Null class. Under Dart’s sound null safety system, types are non-nullable by default, meaning a variable cannot contain null unless its type explicitly permits it at compile time.

The Null Class and Type Hierarchy

The Null class occupies a specific position within Dart’s unified type system:
  • Null is a subtype of all nullable types.
  • The absolute top type in Dart is Object?, which is the supertype of all types, including Null.
  • The non-nullable top type Object does not accept null.
  • The bottom type Never cannot be null (as it represents a state that never completes).

Nullable Type Syntax

To designate a type as nullable, append a question mark (?) to the type declaration. Conceptually, this creates a union type of the base type and the Null class (e.g., String? acts as String | Null).
// Non-nullable type: Memory is guaranteed to hold a String.
String nonNullableString = 'Dart';
// nonNullableString = null; // Static analysis error

// Nullable type: Memory can hold a String or the Null instance.
String? nullableString = null;

Null-Aware Operators

Dart provides specific operators to safely navigate, evaluate, and cast expressions involving null at the syntax level:
  • Null-assertion operator (!): Acts as an explicit cast that the static analyzer recognizes, promoting a nullable expression’s static type to its underlying non-nullable type. It throws a TypeError at runtime if the operand evaluates to null.
int? nullableInt = 5;
int nonNullableInt = nullableInt!;
  • Null-coalescing operator (??): Evaluates to the left operand if it is not null; otherwise, evaluates to the right operand.
String? nullableValue;
String resolvedValue = nullableValue ?? 'Fallback';
  • Null-coalescing assignment operator (??=): Assigns a value to a variable only if that variable currently evaluates to null.
int? counter;
counter ??= 1; 
  • Null-aware access operator (?.): Conditionally accesses a property or method. If the receiver is null, the expression short-circuits and evaluates to null instead of throwing a NoSuchMethodError.
String? text;
int? length = text?.length;
  • Null-aware cascade operator (?..): Performs a sequence of operations on the same object only if the target object is not null.
List<int>? numbers;
numbers?..add(1)..add(2);
  • Null-aware index operator (?[]): Attempts to access an index of a collection only if the collection itself is not null.
List<String>? items;
String? firstItem = items?[0];
  • Null-aware spread operator (...?): Conditionally inserts multiple elements into a collection. If the source collection is null, it is safely ignored rather than throwing an error.
List<int>? nullableList;
List<int> combinedList = [1, 2, ...?nullableList];

Late Initialization

The late modifier alters how the compiler enforces initialization rules. It decouples the declaration of a variable from its initialization, deferring the definite assignment (initialization) check from compile-time to runtime. When applied to a non-nullable variable, it allows the variable to be declared without an immediate value, provided it is initialized before its first read.
late String deferredString;

// Accessing before initialization throws a LateInitializationError
// print(deferredString); 

deferredString = 'Allocated';
The late modifier can also be applied to nullable variables. This enforces that the variable is explicitly initialized before use, allowing developers to distinguish between an uninitialized state (which throws an error if read) and a state explicitly set to null.
late String? explicitlyNullable;

// print(explicitlyNullable); // Throws LateInitializationError

explicitlyNullable = null; // Explicitly initialized to null
print(explicitlyNullable); // Prints 'null'
Tired of Poor Dart Skills? Fix That With Deep Grasping!Learn More