Evolving Label-Directed Tuple Assignments

You may be familiar with standard “tuple shuffles”. In the most common form, you use tuples to rearrange data without intermediate values:

var item1 = "x"
var item2 = "y"

// swap values
(item1, item2) = (item2, item1)
print("\(item1), \(item2)") // "y, x"

You streamline this approach by incorporating tuples into the declaration as well as the value swap:

// declare `item1` and `item2`
var (item1, item2) = ("x", "y")

// swap values
(item1, item2) = (item2, item1)
print("\(item1), \(item2)") // "y, x"

However, you can also use tuple labels to mix and match declarations with values. Right now on Swift Evolution, this is being referred to (incorrectly in my opinion) as a “tuple shuffle”:

// declare `value`
let value = (x: "x", y: "y")

// declare `item1` and `item2`
var (y: item1, x: item2) = value // y, x
print("\(item1), \(item2)") // "y, x"

// use label-based re-assignment
(y: item1, x: item2) = (x: item1, y: item2) //(y "x", x "y")
print("\(item1), \(item2)") // "x, y"

This Swift language feature, regardless of its name, is both obscure, and according to a recent  evolution list discussion, a source of unnecessarily compiler complexity.

Robert Widman has introduced a draft proposal to deprecate label-based declaration:

[This] is an undocumented feature of Swift in which one can re-order the indices of a tuple by writing a pattern that describes a permutation in a syntax reminiscent of adding type-annotations to a parameter list…it can be used to simultaneously [deconstruct] and reorder a tuple…(and)…map parameter labels out of order in a call expression.

Their inclusion in the language complicates every part of the compiler stack, uses a syntax that can be confused for type annotations, contradicts the goals of earlier SE’s (see SE-0060), and is applied inconsistently in the language in general.

There’s been a lively discussion on the Swift Evolution list about the proposal. I thought it was a fairly obvious and simple win. The draft has generated dozens and dozens of replies. Members have discussed both the nuances and possible side effects of the proposed change.

I agree with T.J. Usiyan in disliking the following pattern:

// Declare using labels
let rgba: (r: Int, g: Int, b: Int, a: Int) = (255, 255, 255, 0)

// Declare using re-ordered labels
let argb: (a: Int, r: Int, g: Int, b: Int) = rgba 
// This is the line I have issue with

print(argb.a) // "0"

This unintuitive approach runs counter to Swift’s philosophy of clarity and simplicity. Consider Joe Groff’s default parameter proposal SE-0060 and Austin Zheng’s function argument label type significance proposal SE-0111. Why not ignore label order and focus on type checking? I think the “correct” behavior should act like this instead:


// Declare using re-ordered labels
let argb: (a: Int, r: Int, g: Int, b: Int) = rgba 
// (Int, Int, Int, Int) assigned to (Int, Int, Int, Int)

print(argb.a) // "255"

I’d rename the proposal to “Removing the Ordering Significance of Tuple Argument Labels in Declarations”, and ensure that tuple argument labels aren’t considered when typing the new constant in the previous example.

What do you think?


  • “Why not ignore label order and focus on type checking?”

    This would fundamentally make tuples act like a dictionary and its common usage would be like a typealiased dictionary.

  • I’m not really a Swift programmer, although I may one day try to do more in it, but it seems to me that if something has a label, then the labels should be respected. It seems to me that having labels in a tuple should make it be a hash, or dictionary, or whatever the structure is called in Swift.

  • Tough call. Usiyan’s counter-example felt more intuitive to me personally…even though I see why it’s problematic. I agree with you that the correct thing is to strive for a simple rule that applies to all cases unambiguously.

  • I believe how swift works now is common in other languages.
    In SML a tuple with labels is called a Record.
    A Record is an unordered collection ov labeled values.

    You can assign to a Record with labeled values in any order.