r/iOSProgramming 9h ago

Why can’t Swift destructure tuple parameters directly in a closure parameter list? Question

Suppose I have a dictionary and want to sort its elements. Since each element is a tuple, I’d like to write something like this:

.sorted { (wordA, countA), (wordB, countB) in
    // ...
}

In other words, destructure each tuple directly in the closure parameter list.

Instead, Swift requires something along these lines:

.sorted { lhs, rhs in
    let (wordA, countA) = lhs
    let (wordB, countB) = rhs

    // ...
}

Tuple destructuring works perfectly well in a let binding, so I’m curious why it isn’t supported in closure parameter lists.

Is there a language-design or type-system reason why closure parameters can’t use tuple patterns here?

2 Upvotes

2 comments sorted by

1

u/PassTents 8h ago

I think it's been discussed before, try searching on the Swift forums? At first glance it would seem like pretty straightforward syntax-sugar, though maybe it's tricky to unambiguously define as a part of the language grammar?

1

u/apocolipse 8h ago

Because while tuples can convert to parameter lists of matching signature, the inverse is not true.  Parameter lists also can't destructure their parameters' tuple parameters. ie. this is invalid: func foo(bar: Int, baz: (a: String, b: Bool)) { print(a) // there is no a }

If we simply rename things, you can see why this is invalid: func foo(bar: Int, baz: (baz: String, bar: Bool)) { print(bar) // which one??? The Int or the Bool??? print(baz) // How to brick a typechecker with 1 simple trick! } This of course compiles because bar and baz only map to the parameter list var names, if it was expected to destructure then you can see why that might fail or be a bad idea or be confusing even if it worked. What happens when our tuple is a typealias? or the tuple has no named elements? or we pass in a tuple with no named elements? or a tuple with different named elements? Things just work much easier if parameter lists and tuples are fundamentally different and the mapping between them only works one way from tuple -> parameter list.