switchCase method

void switchCase(
  1. void first(
    1. A value
    )?,
  2. void second(
    1. B value
    )?,
  3. void third(
    1. C value
    )?,
  4. void forth(
    1. D value
    )?,
  5. void fifth(
    1. E value
    )?,
  6. void sixth(
    1. F value
    )?,
  7. void seventh(
    1. G value
    )?,
)

Allow executing custom logic based on the value type in a type safe way.

Prefer using this method over the is operator.

The switchCase method voluntarily forces the code to handle all types that the value can take, whereas is doesn't.

As such, while we can do:

Union2<String, int> union;

if (union.value is int) {
  final value = union.value as int;
  print(value);
}
// Voluntarily do nothing with String

This code has a few issues:

  • it requires a cast
  • it is implicit instead of explicit that String is not handled. This makes the code harder to read: is it a mistake or desired?
  • if in the future the union changes (a type changed or a new type is added), then we may forget to update this specific piece of code.

Instead, we can use switchCase like so:

Union2<String, int> union;

union.switchCase(
  null, // we explicitly don't handle String
  (value) => print(value),
);

This is equivalent to the previous code with a few benefits:

  • no cast

  • not handling a specific type is now explicit: we now know for sure that it's desired.

  • if we later refactor Union2<String, int> into Union2<String, num> or Union3<String, int, Whatever>, than we may have a compile error.

    This ensures that there's no invalid/dead code that we forgot to update.

Implementation

void switchCase(
  void first(A value)?,
  void second(B value)?,
  void third(C value)?,
  void forth(D value)?,
  void fifth(E value)?,
  void sixth(F value)?,
  void seventh(G value)?,
) {
  return this(
    first ?? _noop,
    second ?? _noop,
    third ?? _noop,
    forth ?? _noop,
    fifth ?? _noop,
    sixth ?? _noop,
    seventh ?? _noop,
    _noop,
    _noop,
  );
}