1

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.

shoujs
  • 1,113
  • 1
  • 11
  • 24
  • You never call `next()`. If you would, the output would become `2\n1\nStack(store:[1,2])` – Mr. Xcoder Jun 27 '17 at 07:05
  • @Mr.Xcoder this is a horribly wrong suggestion – user3581248 Jun 27 '17 at 07:12
  • @user3581248 Calling a function you have defined is not a "horribly wrong suggestion". In fact, the accepted answer does this. Of course, changing it to a class is far more convenient, but mine is not "horribly wrong". I only wanted to suggest that `next()` does not get called. – Mr. Xcoder Jun 27 '17 at 07:22
  • @Mr.Xcoder it gets called when you're iterating over the stack. That's the whole point of implementing the `IteratorProtocol`. The accepted answer's point is in its first sentence. – user3581248 Jun 27 '17 at 07:39

1 Answers1

2

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.

Benno Kress
  • 2,637
  • 27
  • 39