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
each
keyword 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 seq
andvar iter
below.This lets us define the return type of the variadic
zip
function 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 iter
is an immutable value, so you can only pass it to functions expecting a non-inoutIteratorProtocol
parameter. That function can dovar copy = iter
to 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
.0
of each nested tuple, and assign it to theiter
property to update it. Then create a tuple of all the.1
of each nested tuple, and return that as the next element.To handle the case of
next
returningnil
, I thought of a trick - to givenextHelper
some side effect:When we do
(repeat nextHelper(each iter))
,nextHelper
runs for every iterator. If any of the iterators returnednil
,anyReachedEnd
would 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.