Home > Software design >  Swift tuple pattern matching fail to compile only for switch statement
Swift tuple pattern matching fail to compile only for switch statement

Time:09-21

I have the following struct:

struct Pair<First, Second> {
    var first: First
    var second: Second

    static func ~= (pattern: (First, Second), value: Pair) -> Bool { /* code */ }
}

Now, the test code:

func test() {
    let tuple = (0, "zero")
    let pair = Pair(0, "zero")
    
    (0, "zero") ~= pair
    tuple ~= pair
    
    switch pair {
    case tuple: return
    case (0, "zero"): return // only this raises an error
    // error: tuple pattern cannot match values of the non-tuple type 'Pair<Int, String>'
    default: return
    }
}

Question: It doesn't seem like it's an issue with matching a tuple literal vs. a tuple instance, since a non-switch version is working fine.

I'm wondering if this is some bug, or there is something I need to know about switch statements.

CodePudding user response:

case tuple: return

This is an "expression pattern." It can employ the ~= operator:

The expression represented by the expression pattern is compared with the value of an input expression using the Swift standard library ~= operator.

case (0, "zero"): return // only this raises an error

This is a "tuple pattern." It has different features and does not support ~=. For example, it supports let bindings to individual elements of the pattern. In this example, 0 and "zero" are nested expression patterns, and so there could be a custom ~= implementations for String or Int patterns that would be applied. But that won't work for a tuple, since it's interpreted as a tuple pattern.

I don't believe there's any way to create a tuple-literal expression pattern. Tuple patterns can only match tuples (which is what the error is saying: "tuple pattern cannot match values of the non-tuple type"). If this is an important feature for you, you should probably discuss on the forums.

The way to implement what you're building is to make Pair Equatable when its elements are Equatable, and then switch on:

case Pair(0, "zero"): return

CodePudding user response:

You are trying to compare a struct with a Tuple. Swift knows will never be the same, therefore it does not allow this comparison. You get the same error if you try to switch on a String and place an Int in the case statement (the error is a little different because Swift does special things for Tuples).

  • Related