when<T, V> function

V when <T, V>(
  1. T value,
  2. Map<T, V Function()> branches
)

The when method replaces the switch statement.

The simplest form of a when method:

when(x, {
  1: () => print('x == 1'),
  2: () => print('x == 2'),
  orElse: () {
    print('x is neither 1 nor 2');
  },
});

when matches its argument against all branches sequantially until a branch condition is satisified.

when can be used either as an expression, or as a statement. If it is used as an expression, the value of the satisfied branch becomes the value of the expression. And if it is used as a statement, the values of the branches are ignored.

The orElse branch is checked if none of the other branches are satisified. The orElse is mandatory, when not supplied it will return null.

If many cases should be handled the same way, the branch condition can be a List:

when(x, {
  [0, 1]: () => print('x == 0 or x == 1'),
  orElse: () => print('otherwise'),
});

Unlike the switch statement in dart, we can use arbitary expressions as branch conditions:

when(x, {
  int.parse(s): () => print('s encodes x'),
  orElse: () => print('s does not encode x'),
});

Using the isIn and isNotIn methods we can also check if the value is in a List:

when(x, {
  isIn(range(0, to: 10)): () => print('x is in the range'),
  isIn(validNumbers): () => print('x is valid'),
  isNotIn(range(10, to: 20)): () => print('x is outside the range'),
  orElse: () => print('none of the above'),
});

It is also possible to check if a value isType or isNotType:

bool hasPrefix(dynamic x) {
  return when(x, {
    isType<String>(): () => x.startsWith('prefix'),
    orElse: () => false,
  });
}

Note: There is currently no smartcasting in place so you might not get autocompletion on methods and properties of the given type.

Implementation

V when<T, V>(T value, Map<T, V Function()> branches) {
  assert(branches != null && branches.isNotEmpty);

  var hasElse = false;
  for (var key in branches.keys) {
    if ((key == value) ||
        (key is List && key.contains(value)) ||
        (key is _WhenCheck && key(value))) {
      return branches[key]();
    }
    hasElse = !hasElse ? key == orElse : hasElse;
  }
  if (hasElse) return branches[orElse]();
  return null;
}