Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A late final field in Dart is a class-level variable that combines deferred initialization (late) with strict runtime immutability (final). It allows a non-nullable field to bypass compile-time definite assignment checks, deferring its initialization until runtime, while guaranteeing that the field’s reference can only be assigned exactly once.

Syntax

// 1. Lazy Initialization (Assigned at declaration)
late final Type fieldName = expression;

// 2. Deferred Assignment (Unassigned at declaration)
late final Type fieldName;

Core Mechanics

The behavior of a late final field depends on whether it is declared with an initializer.

1. With an Initializer (Lazy Evaluation)

When a late final field is declared with an assignment, the evaluation of the right-hand expression is deferred.
  • The expression is executed only upon the first read access of the field.
  • Once evaluated, the result is permanently bound to the field.
  • Because it is final, the field cannot be reassigned after this initial lazy evaluation.
class EvaluationExample {
  // _expensiveComputation() is not called during instantiation.
  // It is called exactly once, the first time `value` is read.
  late final int value = _expensiveComputation();

  int _expensiveComputation() {
    return 42;
  }
}

2. Without an Initializer (Deferred Assignment)

When declared without an assignment, the field acts as a write-once variable whose initialization is detached from the class constructor.
  • Write-Once: The field can be assigned a value at any point during runtime, but strictly only once.
  • Runtime Enforcement: Any attempt to reassign the field after its initial assignment will throw a LateInitializationError.
  • Read Before Write: Attempting to read the field before it has been assigned will also throw a LateInitializationError.
class AssignmentExample {
  late final String token;

  void initializeToken(String value) {
    token = value; // Valid: First assignment
  }

  void reassignToken() {
    token = "new_token"; // Throws LateInitializationError: Field 'token' has already been initialized.
  }

  void readToken() {
    print(token); // Throws LateInitializationError if called before initializeToken()
  }
}

Memory and State Implications

By using late final, the Dart analyzer shifts the safety guarantees of non-nullable types from compile-time to runtime. Standard final fields require memory allocation and assignment before the constructor body executes (via declaration or initializer lists). A late final field allocates the memory for the reference, but leaves the memory uninitialized (or points it to a hidden sentinel value) until the runtime assignment occurs, at which point the memory address is locked.
Master Dart with Deep Grasping Methodology!Learn More