I have a wrapper that wraps a sequence:
struct SequenceWrapper<T>: SequenceType {
var sequence: AnySequence<T>
func generate() -> AnyGenerator<T> {
return sequence.generate()
}
}
let wrapper = SequenceWrapper(sequence: AnySequence(1 ... 10))
If I make two generators and call next() on both, nothing strange happens:
let generator = wrapper.generate()
let another = wrapper.generate()
generator.next() // 1
another.next() // 1
So far, so good. However, if I first call dropFirst() on my wrapper, I get strange behaviour:
let wrapper = SequenceWrapper(sequence: AnySequence(1 ... 10))
let trimmed = wrapper.dropFirst()
let generator = trimmed.generate()
let another = trimmed.generate()
generator.next() // 2
another.next() // 3, huh?
If I use dropLast() instead of dropFirst(), the outputs are 1 and 1, as expected.
If I don't use the wrapper struct I made, but a direct AnySequence instance instead, nothing out of the ordinary happens:
let sequence = AnySequence(1 ... 10)
let trimmed = sequence.dropFirst()
let generator = trimmed.generate()
let another = trimmed.generate()
generator.next() // 2
another.next() // 2, as expected
I can't make any sense of this. What's going on here?
You would have to debug through the behavior to understand the specific behavior, but this most likely happens because SequenceType is not required to be iterable multiple times.
SequenceTypemakes no requirement on conforming types regarding whether they will be destructively "consumed" by iteration. To ensure non-destructive iteration, constrain your sequence toCollectionType.As a consequence, it is not possible to run multiple for loops on a sequence to "resume" iteration:
for element in sequence { if ... some condition { break } } for element in sequence { // Not guaranteed to continue from the next element. // [mine: not guaranteed to restart from the beginning either] }
SequenceTypemakes no requirement about the behavior in that case. It is not correct to assume that a sequence will either be "consumable" and will resume iteration, or that a sequence is a collection and will restart iteration from the first element. A conforming sequence that is not a collection is allowed to produce an arbitrary sequence of elements from the second generator.
In other words, the two generators that you get from calling generate() twice are not guaranteed to not interfere with one another. In fact, it's legal for a type to implement both SequenceType and GeneratorType and implement generate() as return self. Any shared state (from member references, or if the sequence itself is a reference type) will be shared across generators, which is why you should only make one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With