This tutorial explains what is the triple dot (`...`) spread operator in Dart and how to use it.

Since version 2.3, Dart adds a new operator called spread which uses three dots (`...`) notations. It can be used to extend the elements of a `Collection`. The examples below show the usage of the notation on `List`, `Set`, and `Map`.

## Usage on `List`

Prior to Dart 2.3, we have to use `addAll` to combine two `List` instances. Now, the spread operator makes it easier for us to do the same thing.

``````  List<int> l1 = [1, 2, 3];
List<int> result = [0, ...l1];
print(result);``````

In the example above, the `result` is generated by concatenating an element (`0`) with a `List` (`l1`).

Output:

``  [0, 1, 2, 3]``

You can also use triple dot for combining two `List` instances.

``````  List<int> l1 = [1, 2, 3];
List<int> l2 = [4, 5];
List<int> result = [...l1, ...l2];
print(result);``````

Output:

``  [1, 2, 3, 4, 5]``

Nested assignment is also possible

``````  List<int> result = [...[0, ...l1, ...l2], 6];
print(result);``````

First, it combines the 0 element with `l1` and `l2` which generates a `List`. The result is then concatenated to the outer `List` with the `6` element.

Output:

``  [0, 1, 2, 3, 4, 5, 6]``

What happens if you try to use the spread operator with a `null` `List`.

``````  List<int> nullList = null;
List<int> result = [...l1, ...nullList];
print(result);``````

You will get the following error:

``````  Unhandled exception:
NoSuchMethodError: The getter 'iterator' was called on null.``````

Fortunately, Dart also supports null-aware operator for `spread`. Just add `?` symbol after the triple dot `...`.

``````  List<int> nullList = null;
List<int> result = [...l1, ...?nullList];
print(result);``````

By using the null-aware operator, the value will be checked first and if it's `null`, it will be ignored.

Output:

``  [1, 2, 3]``

You can also use `if` condition to determine whether the `List` should be concatenated or not.

``````  bool condition = false;
List<int> result = [...l1, if (condition) ...l2];
print(result);``````

As the value of `condition` is `false` in the example above, `l2` will be ignored.

It can also be used on `Future` by adding `await` after the triple dot (`...`) notation.

``````  Future<List<int>> l1 = Future.value([1, 2, 3]);
Future<List<int>> l2 = Future.value([3, 4, 5]);
List<int> result = [...await l1, ...await l2];
print(result);``````

Output:

``  [1, 2, 3, 4, 5]``

## Usage on `Set`

Spread operator can also be used on `Set`. You can combine multiple `Set` instances and the result is the union of all `Set` instances since a `Set` must have unique elements.

``````  Set<int> s1 = {1, 2, 3};
Set<int> s2 = {3, 4, 5};
Set<int> result = {...s1, ...s2};
print(result);``````

Output:

``  {1, 2, 3, 4, 5}``

Using nested spread operator is also possible.

``````  Set<int> s1 = {1, 2, 3};
Set<int> s2 = {3, 4, 5};
Set<int> result = {...{...s1, ...s2}, 5, 6};
print(result);``````

Output:

``  {1, 2, 3, 4, 5, 6}``

The operator will throw error when applied on a `null` `Set`.

``````  Set<int> s1 = {1, 2, 3};
Set<int> nullSet = null;
Set<int> result = {...s1, ...nullSet};
print(result);``````
``````  Unhandled exception:
NoSuchMethodError: The getter 'iterator' was called on null.``````

It can be handled using null-aware `?` notation which ignores `null` value.

``````  Set<int> s1 = {1, 2, 3};
Set<int> nullSet = null;
Set<int> result = {...s1, ...?nullSet};
print(result);``````

Output:

``  {1, 2, 3}``

`if` conditional is supported as well.

``````  Set<int> s1 = {1, 2, 3};
Set<int> s2 = {3, 4, 5};
bool condition = false;
Set<int> result = {...s1, if (condition) ...s2};
print(result);``````

Output:

``  {1, 2, 3}``

As does `Future`

``````  Future<Set<int>> s1 = Future.value({1, 2, 3});
Future<Set<int>> s2 = Future.value({3, 4, 5});
Set<int> result = {...await s1, ...await s2};
print(result);``````

Output:

``  {1, 2, 3, 4, 5}``

## Usage on `Map`

The spread operator can also be used for `Map`. What will happen if we try to combine multiple `Map` instances where a key can presence in more than one `Map`. To find the answer, look at the example below

``````  Map<int, String> m1 = {1: '1-1', 2: '1-2'};
Map<int, String> m2 = {2: '2-2', 3: '2-3'};
Map<int, String> result = {...m1, ...m2};
print(result);``````

If you run the code, you will find that the value is always overridden by the latest `Map`.

Output:

``  {1: 1-1, 2: 2-2, 3: 2-3}``

Here is an example with nested spread operator.

``````  Map<int, String> m1 = {1: '1-1', 2: '1-2'};
Map<int, String> m2 = {2: '2-2', 3: '2-3'};
Map<int, String> result = {...{...m1, ...m2}, 3: '3', 4: '4'};
print(result);``````

Output:

``  {1: 1-1, 2: 2-2, 3: 3, 4: 4}``

Like the other `Collection` types, applying triple dot on `null` will throw `NoSuchMethodError`.

``````  Map<int, String> m1 = {1: '1-1', 2: '1-2'};
Map<int, String> nullMap = null;
Map<int, String> result = {...m1, ...nullMap};
print(result);``````
``````  Unhandled exception:
NoSuchMethodError: The getter 'entries' was called on null.``````

And it can be handled using null-aware operator.

``````  Map<int, String> m1 = {1: '1-1', 2: '1-2'};
Map<int, String> nullMap = null;
Map<int, String> result = {...m1, ...?nullMap};
print(result);``````

Output:

``  {1: 1-1, 2: 1-2}``

Using `await` is also possible if you need to get value from a `Future`.

``````  Future<Map<int, int>> future1 = Future.value({1: 1, 2: 2});
Future<Map<int, int>> future2 = Future.value({3: 3});
Map<int, int> result = {...await future1, ...await future2};
print(result);``````

Output:

``  {1: 1-1, 2: 2-2, 3: 2-3}``

That's how to use the spread operator in Dart. It makes us easier to combine collections while also makes the code cleaner.