Enum tuple case composing/decomposing disparity

In this example:

typealias Tuple = (first: Int, second: Int)

enum TupleEnum {
    case tuple(Tuple)
}

func foo(value: TupleEnum) {
    switch value {
    // case let .tuple(t: Tuple): break // no brainer
    // case let .tuple((first, second)): break // no brainer
    case let .tuple(first, second): break // βœ…
    }
    TupleEnum.tuple(first: 0, second: 0) // πŸ›‘ Enum case 'tuple' expects a single parameter of type 'Tuple' (aka '(first: Int, second: Int)')
}

I can match an enumeration case that takes a tuple using two separate variables, but I can't do the inverse: construct that case with two separate variables.

Similarly in this example:

typealias Tuple = (first: Int, second: Int)

enum PairEnum {
    case pair(first: Int, second: Int)
}

func bar(e: PairEnum) {
    switch e {
    // case let .pair(first, second): break // no brainer
    case let .pair(v: Tuple): break // βœ…
    }
    let tuple = Tuple(first: 0, second: 0)
    PairEnum.pair(tuple) // πŸ›‘ Enum case 'two' expects 2 separate arguments
}

I can match an enumeration case that takes two separate variables using a tuple, but can't do the inverse: construct that case with a tuple.

Could we fix it one way or another and make the composing & decomposing behaviours aligned?

2 Likes

This is covered in:

Specifically:

Ungating the pattern matching revision reveals that a rather large amount of code is relying upon the existing Swift 3 pattern matching behavior around tuple element labels and neither the proposal nor the acceptance rationale provide a clear answer for how we wish to resolve this (see the issue thread ). If the community still feels that a source breaking change of this magnitude in the name of consistency is warranted, a revision that clearly spells out the rules for pattern matching should be drafted.

Simply pointing out that there is a disparity doesn't justify changing it; if it was too source breaking for Swift 4, it's hard to see how it's justifiable for Swift 6, but if you have a strong argument that hasn't been considered then by all means...

1 Like

Do you think aligning the rules towards more permissive composing rules (so the above red bullets are turned into green) is source breaking?

You mean to say that you want to revoke most of SE-0155? What is your rationale for doing that?

Even more fun, by passing to a generic context, you can do that:

enum PairEnum {
  case pair(first: Int, second: Int)
}

func apply<T, U>(_ f: (T)->U, _ x: T) -> U {
  return f(x)
}

let tuple = (first: 0, second: 0)
let result = apply(PairEnum.pair, tuple)    // This works!

…you just can’t do it directly, because of SE–0029.

6 Likes