Single-element labeled tuples?

I found myself wanting either a single element tuple or a labelled return value. I suppose you could encode that in the name but something like this would be nice.

func fetch() -> more: Bool  {
      // do work, if there is more to get return true 
     return true
}

let more = fetch().more

This lets you document your return value and make you check all your call sites if you decide to change the meaning of the return value. In other words, the same advantages you get with parameter labels and adds to the safety of the language. So if I changed more to mean done, then the compiler would make me change it everywhere where the return value meaning changed.

func fetch() -> done: Bool  {
      // do work, if there is more to get return false. 
     return false
}

let done = fetch().done

This could also be accomplished with a single element tuple.

    func fetch() -> (more: Bool) {
        // do work, if there is more to get return true 
       return (more: true) 
    }
    let more = fetch().more

It seems that for completeness both could be supported and it would avoid the special case of why you can't label return values. Although the latter would work if it is decided that only tuples can have labels. Also, it might be good to enforce that if you specify it, you must use the label so that as in the first example, you changed the meaning, you would get errors if you did not update the labels at the call sites.

This seems like, on initial thought, this change could be additive and not source breaking but I could be wrong. Probably not ABI stable though, I am not sure about that.

1 Like

This is actually a great solution! You saved my day :sunny:

TIL that single-element labeled tuples are in the language in at least one place: How do you get labeled associated values from Mirror children? - #3 by Jessy

I like them as placeholders for when I know something else is coming, but it's not worth making a struct for because it will only be the return type for one function. And I wish I didn't need this workaround:

public enum Tuple { }

public extension Tuple {
  /// Used to create a 2-tuple, as a single-element tuple can't have a label.
  typealias Placeholder = Void

  /// Stuff an element into a tuple that will have a labeled first element
  /// when converted to a return value.
  static func `init`<LabeledElement>(
    _ labeledElement: LabeledElement
  ) -> (LabeledElement, Placeholder) {
    ( labeledElement, Placeholder() )
  }
}
func makeIllustrations() -> [(image: String, Tuple.Placeholder)] {
  [ ( image: "🐻", Tuple.Placeholder() ),
    Tuple.`init`("🍯"),
    ( image: "🐝", () )
  ]
}

XCTAssertEqual(makeIllustrations()[1].image, "🍯")
1 Like