[Review] SE-0408: Pack Iteration

+1 This is needed functionality, and this seems to me to be the natural spelling for pack iteration in Swift.

Also excited for the mentioned future extension to guard let.

1 Like
Sidebar discussion about iterating over a pack and a collection at the same time

I think this is a pretty good solution, and sorry if this is so much of a Future Direction as to be off-topic, but is there space in this syntax to allow iterating over a pack and a collection at the same time? In particular, I can easily imagine it would be nice to have some equivalent of enumerated:

for (i, next) in repeat (each 0..., each element) {
  print(i, next)
}

I don’t think this exact syntax works because the compiler can’t prove 0... is at least as long as each element. Maybe it’ll have to use some function like

// UNTESTED

// A bit clunky, used to construct a pack
// with the same length as another pack
// but a different element type.
// No idea if it works.
typealias Second<FirstType, SecondType> = SecondType

func take<each PackElement, Items: Sequence>(
  from items: Items,
  matching packElement: repeat each PackElement
) -> (repeat Second<each PackElement, Items.Element>) {
  var iter = items.makeIterator()
  return (repeat (each packElement, iter.next()!).1)
}

for (i, next) in repeat (
  take(from: 0..., matching: each element),
  each element
) {
  print(i, next)
}

Now that I write that out I think that makes sense. It’s a bit verbose, but it makes the collection-to-pack conversion explicit.

1 Like

The untested code actually already works under this proposal! But because you're making a new iterator every time take is called, i will always be 0. Here's the modified version that will produce the desired behavior (it also already works):

func enumerated<each T>(_ t: repeat each T) -> (repeat (Int, each T)) {
  func advance(_ i: inout Int) -> Int {
    defer { i = i + 1 }
    return i
  }
  var index = 0

  return (repeat (advance(&index), each t))
}


func variadic<each Element>(element: repeat each Element) {
  let enumerated = enumerated(repeat each element)
  for (i, el) in repeat each enumerated {
    print("\(i): \(el)")
    // 0: first
    // 1: 3
    // 2: true
  }
}

variadic(element: "first", 3, true)

Also this example helped to uncover a bug in the current implementation: getting rid of enumerated variable and replacing it with the call to the enumerated function will crash the compileršŸ˜… Will be working on fixing that.

8 Likes

And to do that with an arbitrary collection, you’d use an Iterator instead of Int! Thanks, Sima.

1 Like

This proposal has been accepted, thank you everyone!

3 Likes