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 logical-or pattern (|) is a composite pattern that matches a value if any of its constituent subpatterns successfully match. It evaluates subpatterns sequentially from left to right and short-circuits, halting evaluation immediately upon the first successful subpattern match.

Pattern Contexts and Refutability

Logical-or patterns are strictly refutable. They are only permitted in refutable contexts where a match failure alters control flow, such as switch cases, switch expressions, and if case statements. They cannot be used in irrefutable contexts, such as pattern variable declarations or pattern assignments. The compiler prohibits this because it cannot guarantee at compile time which branch of the logical-or pattern will execute, making deterministic variable initialization impossible.
void main() {
  int number = 2;
  
  // Valid: Refutable context (switch statement)
  switch (number) {
    case 1 | 2 | 3:
      print('Matches 1, 2, or 3');
      break;
    default:
      print('No match');
  }

  // Invalid: Irrefutable context (variable declaration)
  // Compilation Error: Refutable pattern '1 | 2' cannot be used in an irrefutable context.
  // var (1 | 2) = number; 
}

Evaluation Mechanics

  1. The incoming value is tested against the left-hand subpattern.
  2. If the left-hand subpattern matches, the logical-or pattern succeeds, and the right-hand subpattern is completely ignored (short-circuit evaluation).
  3. If the left-hand subpattern fails, the value is then tested against the right-hand subpattern.
  4. The logical-or pattern fails if and only if all of its subpatterns fail to match.

Variable Binding Rules

When a logical-or pattern includes variable bindings (extracting values into local variables), Dart enforces strict structural rules to ensure type safety. If any subpattern binds a variable, all subpatterns within the logical-or pattern must bind the exact same set of variables, and those variables must resolve to the exact same types.
void main() {
  var myRecord = (10, 20);

  // Valid Binding: Both branches bind a single integer variable named 'x'.
  if (myRecord case (int x, _) | (_, int x)) {
    print(x);
  }

  // Invalid Binding (Missing Variable):
  // Compilation Error: The right branch binds 'y' instead of 'x'. 
  // if (myRecord case (int x, _) | (int y, _)) {
  //   print(x);
  // }

  // Invalid Binding (Type Mismatch):
  // Compilation Error: 'x' is an int in the left branch, but a String in the right branch.
  // if (myRecord case (int x, _) | (String x, _)) {
  //   print(x);
  // }
}

Precedence and Nesting

The logical-or operator (|) has the lowest precedence among pattern operators. It binds less tightly than the logical-and pattern (&), relational patterns (>, <=, etc.), and cast patterns (as). To override default precedence, subpatterns must be wrapped in parentheses.
void main() {
  int value = 2;

  // Evaluates as: (1) | (2 & >0)
  // Matches if the value is 1, OR if the value is both 2 and greater than 0.
  if (value case 1 | 2 & > 0) {
    print('Matched default precedence');
  }

  // Evaluates as: (1 | 2) & >0
  // Matches if the value is either 1 or 2, AND is greater than 0.
  if (value case (1 | 2) & > 0) {
    print('Matched overridden precedence');
  }
}
Logical-or patterns can be nested inside destructuring patterns—such as object, record, or list patterns—allowing for localized alternative matching within a larger data structure.
void main() {
  var data = [1, 'b'];

  // Logical-or patterns nested inside a list pattern
  if (data case [1 | 2, 'a' | 'b']) {
    print('Matched nested logical-or');
  }
}
Master Dart with Deep Grasping Methodology!Learn More