Value Pack Expansion and Single Element Tuples

I'm having an issue with some code I'm writing that uses pack expansion and macros

The fundamental issue is that (repeat each foo) doesn't expand to a tuple if there is only a single value:

func tuple<each T>(foos: (repeat each T)) -> (repeat each T) {
  (repeat each foos)
}
let singleElementTuple = tuple(foos: (1))
singleElementTuple.0 // Value of type 'Int' has no member '0'
let twoElementTuple = tuple(foos: (1, 2))
twoElementTuple.0 // Works fine

In regular code this is mostly-fine, but in generated code (such as a macro) it is a little annoying as I need to special-case the single-element case. Is there any better way to deal with this?

1 Like

I don't think so, because not only do packs support single elements, but also, zero elements:

tuple(foos: ()).0 //🙂‍↔️

Maybe this is helpful, for the special casing?

func isReallyTuple<each Element>(_ element: (repeat each Element)) -> Bool {
  var hasFirstElement = false
  for _ in repeat (each Element).self {
    if hasFirstElement { return true }
    else { hasFirstElement = true }
  }
  return false
}

One element tuples were pitched and rejected in [Pitch] One-Element Tuples.

Maybe you want something like this?

func first<T, each U>(_ tuple: (T, repeat each U)) -> T {
  return tuple.0
}

That crashes the compiler in the latest Xcode beta. Do you actually have it working?

I tried something like this, but for my use case it is actually a (repeat (ConcreteType, each ParameterPackType)) so in order to make that work I'd need to provide a value of ConcreteType in order to make it work. Fortunately, it isn't a huge issue for the logic to be conditional on whether or not there is one or multiple elements (0 elements is actually another interesting case). I was just wondering if there was some language feature I missed which cleaned this up but it seems like that isn't the case.