swiftsequencemutating-functioniterator-protocol

Why mutating function next does not change the struct (conforming to Sequence and IteratorProtocol) after the iteration?


I write a stack struct, and make it conforming to IteratorProtocol and Sequence protocol. The next function is mutating. So I suppose the iteration of the stack will mutate the struct.

import Foundation


struct Stack<Element> {
    var store:[Element] = []

    mutating func push(_ element:Element) {
        store.append(element)
    }

    mutating func pop() -> Element? {
        return store.popLast()
    }
}


extension Stack: Sequence, IteratorProtocol {

    mutating func next() -> Element? {
        return pop()
    }

}

var stack = Stack<Int>()
stack.push(1)
stack.push(2)
stack.push(3)


for s in stack {
    print(s)
}

print(stack)

Here is the console output: enter image description here

I don't understand why the stack is unchanged. I suppose it become empty after the mutating next() calls.


Solution

  • Your for ... in-Loop works on a copy of stack and never changes the stack itself. If you were to call next() yourself, the pop() would modify the stack as you can see here:

    import Foundation
    
    struct Stack<Element> {
        var store: [Element] = []
    
        mutating func push(_ element:Element) {
            store.append(element)
        }
    
        mutating func pop() -> Element? {
            return store.popLast()
        }
    }
    
    
    extension Stack: Sequence, IteratorProtocol {
        mutating func next() -> Element? {
            return pop()
        }
    }
    
    var stack = Stack<Int>()
    stack.push(1)
    stack.push(2)
    stack.push(3)
    
    for s in stack {
        print(s)
    }
    
    stack.next()
    
    print(stack.store)
    

    Output:

    3
    2
    1
    [1, 2]
    

    However as @user3581248 pointed out in the comments, making Stack a class instead of a struct (and removing mutating from its functions) gives you the desired behavior.