According to SE-0398, we can now create types with a variable number of generic type parameters. The document uses ZipSequence as an example:
In the generic parameter list of a generic type, the
eachkeyword declares a generic parameter pack, just like it does in the generic parameter list of a generic function. The types of stored properties can contain pack expansion types, as inlet seqandvar iterbelow.This lets us define the return type of the variadic
zipfunction as follows:struct ZipSequence<each S: Sequence>: Sequence { typealias Element = (repeat (each S).Element) let seq: (repeat each S) func makeIterator() -> Iterator { return Iterator(iter: (repeat (each seq).makeIterator())) } struct Iterator: IteratorProtocol { typealias Element = (repeat (each S).Element) var iter: (repeat (each S).Iterator) mutating func next() -> Element? { return ... } } }
It unfortunately does not show how to implement the next method.
I tried implementing it as:
(repeat (each iter).next()!)
This produces the error:
Cannot use mutating member on immutable value of type 'τ_1_0.Iterator'
I know that I did not handle the case of next returning nil. Let's just assume that the sequences are all infinite - I just want to get to something that at least compiles first. Handling next returning nil is the least of my concerns, if I can't even write something that compiles.
How can I implement this next method?
Apparently
each iteris an immutable value, so you can only pass it to functions expecting a non-inoutIteratorProtocolparameter. That function can dovar copy = iterto make it mutable, and return the modifiedcopy, together with the next element:Then, if we do
(repeat nextHelper(each iter)), we get a nested tuple structured like this:All we need to do now is to create a tuple of all the
.0of each nested tuple, and assign it to theiterproperty to update it. Then create a tuple of all the.1of each nested tuple, and return that as the next element.To handle the case of
nextreturningnil, I thought of a trick - to givenextHelpersome side effect:When we do
(repeat nextHelper(each iter)),nextHelperruns for every iterator. If any of the iterators returnednil,anyReachedEndwould be set to true.I do think this is a bit "nasty". Perhaps there will be better ways to do this in future versions of Swift.