Refutability of Patterns

There are two types of patterns: refutable and irrefutable. On the premise of type matching, when a pattern may not match the value to be matched, the pattern is referred to as a refutable pattern; on the contrary, when a pattern always matches the value, the pattern is referred to as an irrefutable pattern.

The patterns described above are specified as follows:

Constant patterns are refutable. In the following example, 1 in the first case and 2 in the second case may be different from the value of x.

func constPat(x: Int64) {
    match (x) {
        case 1 => "one"
        case 2 => "two"
        case _ => "_"
    }
}

Wildcard patterns are irrefutable. In the following example, _ can always match the value of x.

func wildcardPat(x: Int64) {
    match (x) {
        case _ => "_"
    }
}

Binding patterns are irrefutable. In the following example, the binding pattern a can always match the value of x.

func varPat(x: Int64) {
    match (x) {
        case a => "x = ${a}"
    }
}

Tuple patterns are irrefutable only when each pattern contained in the tuple pattern is irrefutable. In the following example, (1, 2) and (a, 2) may not match the value of x. Therefore, they are refutable. (a, b) can match any value of x. Therefore, it is irrefutable.

func tuplePat(x: (Int64, Int64)) {
    match (x) {
        case (1, 2) => "(1, 2)"
        case (a, 2) => "(${a}, 2)"
        case (a, b) => "(${a}, ${b})"
    }
}

Type patterns are refutable. In the following example (assuming that Base is the parent class of Derived and Base implements interface I), the runtime type of x may be neither Base nor Derived. Therefore, both a: Derived and b: Base are refutable.

interface I {}
open class Base <: I {}
class Derived <: Base {}

func typePat(x: I) {
    match (x) {
        case a: Derived => "Derived"
        case b: Base => "Base"
        case _ => "Other"
    }
}

Enum patterns are irrefutable only when the corresponding enum type has only one constructor with parameters, and each pattern contained in the enum pattern is irrefutable. For the definitions of E1 and E2 in the following example, A(1) in the function enumPat1 is refutable, and A(a) is irrefutable; while B(b) and C(c) in the function enumPat2 are refutable.

enum E1 {
    A(Int64)
}

enum E2 {
    B(Int64) | C(Int64)
}

func enumPat1(x: E1) {
    match (x) {
        case A(1) => "A(1)"
        case A(a) => "A(${a})"
    }
}

func enumPat2(x: E2) {
    match (x) {
        case B(b) => "B(${b})"
        case C(c) => "C(${c})"
    }
}