Search code examples
swiftenumerate

EnumerateGenerator and Tuple


enumerate function returns type EnumerateGenerator. But in Swift you are allowed to use that and assign to tuple. How does EnumerateGenerator become a tuple?

Definition: func enumerate<Seq : SequenceType>(seq: Seq) -> EnumerateGenerator<Seq.Generator>

for (index, value) in enumerate([1, 2, 3, 4, 5]) {
       // How does EnumerateGenerator become a tuple?
}

In definition of EnumerateGenerator, Element is typealiased to a tuple, am I correct to assume that calling enumerate() is the same as calling EnumerateGenerator->next?

struct EnumerateGenerator<Base : GeneratorType> : GeneratorType, SequenceType {
    typealias Element = (index: Int, element: Base.Element)
    mutating func next() -> Element?
    typealias Generator = EnumerateGenerator<Base>
    func generate() -> EnumerateGenerator<Base>
}

Solution

  • From "For-In Statement" in the Swift documentation:

    A for-in statement allows a block of code to be executed once for each item in a collection (or any type) that conforms to the SequenceType protocol.

    The generate method is called on the collection expression to obtain a value of a generator type—that is, a type that conforms to the GeneratorType protocol. The program begins executing a loop by calling the next method on the stream. If the value returned is not None, it is assigned to the item pattern, the program executes the statements, and then continues execution at the beginning of the loop. Otherwise, the program does not perform assignment or execute the statements, and it is finished executing the for-in statement.

    So

    for (index, value) in enumerate([1, 2, 3, 4, 5]) {
        // ...
    }
    

    is identical to

    let enumGenerator = enumerate([1, 2, 3, 4, 5])
    var genFunc = enumGenerator.generate()
    while let (index, value) = genFunc.next() {
        // ...
    }
    
    • let enumGenerator = enumerate([1, 2, 3, 4, 5]) returns a EnumerateGenerator<Seq.Generator> (in this case a EnumerateGenerator<IndexingGenerator<Array<Int>>>). This conforms to the SequenceType protocol.

    • var genFunc = enumGenerator.generate() returns again a EnumerateGenerator<Seq.Generator> (probably a copy of the enumGenerator). This conforms to the GeneratorType protocol.

    • genFunc.next() returns Element? where Element is a type alias for (index: Int, element: Base.Element).

      In this case, next() returns (index: Int, element: Int)?. This next function returns optional tuples until the array is exhausted, where it returns nil.