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.

The spread operator (...) is a syntactic construct used within collection literals (List, Set, and Map) to unpack and insert the elements of an evaluated Iterable or Map directly into the surrounding collection. Additionally, in modern Dart (Dart 3 and later), the ... syntax functions as a rest element in pattern matching to destructure remaining elements from collections. It evaluates the expression on its right side and yields each element sequentially into the new collection’s memory space or binds them to a variable.

Syntax Mechanics

When used in collection literals, the operator is placed immediately preceding the collection identifier or expression.
var iterableExpression = [2, 3];
var mapExpression = {'b': 2, 'c': 3};

// Unpacking an Iterable into a List or Set
var combinedList = [1, ...iterableExpression, 4];
var combinedSet = {1, ...iterableExpression, 4};

// Unpacking a Map into another Map
var combinedMap = {'a': 1, ...mapExpression, 'd': 4};
When used as a rest element in pattern matching, it captures the un-matched remainder of a collection:
var numbers = [1, 2, 3, 4, 5];
var [first, ...rest] = numbers; // first is 1, rest is [2, 3, 4, 5]

Execution Semantics

When the Dart runtime encounters a spread operator within a collection literal, it performs the following operations based on the target collection type:
  • Iterables (List, Set): The runtime implicitly accesses the .iterator of the spread expression. It loops through moveNext(), appending each current value to the surrounding collection literal.
  • Maps (Map): The runtime iterates over the .entries property of the source map, inserting each key-value pair into the surrounding map literal.
  • Collision Resolution: If spreading introduces duplicate elements or keys, Dart handles collisions based on the collection type’s inherent constraints:
    • Sets: Sets ignore duplicate elements. If a collision occurs, the first (left-most) element is retained, and subsequent duplicates are discarded.
    • Maps: Maps require unique keys. If a key collision occurs, the right-most (latest) value silently overwrites the preceding value.

The Null-Aware Spread Operator (...?)

The standard spread operator requires a non-null operand. In modern Dart with sound null safety, attempting to use the standard spread operator on a statically typed nullable variable results in a compile-time error. To safely unpack collections that may evaluate to null, Dart provides the null-aware spread operator (...?). If the operand of ...? is null, the operator short-circuits, yields no elements, and allows the surrounding collection literal to continue evaluation without throwing an error.
List<int>? nullableIterable;

// Compile-time error: An expression whose value can be 'null' must be null-checked before it can be dereferenced.
// var listA = [1, 2, ...nullableIterable]; 

// Safely evaluates to [1, 2] if nullableIterable is null
var listB = [1, 2, ...?nullableIterable]; 

Static Type Constraints

The Dart analyzer enforces strict type checking on spread expressions to ensure type safety within the resulting collection:
  1. Lists and Sets: When spreading into a List<T> or Set<T>, the spread expression must possess a static type of Iterable<S>, where S is assignable to T.
  2. Maps: When spreading into a Map<K, V>, the spread expression must possess a static type of Map<J, U>, where J is assignable to K, and U is assignable to V.
If these assignability constraints are not met, the compiler emits a static type error.
List<int> integers = [1, 2, 3];
List<String> strings = ["a", "b"];

// Compile-time error: The element type 'String' can't be assigned to the list type 'int'.
// List<int> combined = [0, ...integers, ...strings]; 
Master Dart with Deep Grasping Methodology!Learn More