Why implementation of the sequence protocol is said destructive?

Is implementation of sequence protocol , destructive ? Why and how!

Sequence type is said to provide sequential, iterated access of its elements. 
Think of a sequence generator which can be used to create user id's, from a starting point.
 

public struct UserIdSequenceGenerator: Sequence {

    private var startId: Int

    

    public init(startId: Int){

        self.startId = startId

    }

}


extension UserIdSequenceGenerator: IteratorProtocol {

    public mutating func next() -> Int? {

        defer {

            startId += 1

        }

        return startId

  

    }

}


Requirements on implementing Sequence Protocol.


First Approach.

Override makeIterator()method which returns IteratorProtocol object. 


Second Approach

Make the UserIdSequenceGenerator Confirm to IteratorProtocol itself and implement next(). We have used second approach in the above code.


Finally the code in Action looks like seen below.


var sequence = UserIdSequenceGenerator(startId: 10)


for userId in sequence {

    print("User Id \(userId)")

}



Can you guess what will be output of the for loop execution?

It will start printing user id from 10 , but would end up in infinite loop.


This means Sequence protocol does not know where to stop and so let's fix this infinite loop thing. There are two approaches.


First Approach - have a break condition in for loop

One of the way is to have a break condition in the for loop itself.


for userId in sequence {

    if userId == 15 {

        break

    }

    print("User Id \(userId)")

}



Second Approach - tweak the next() method to return nil when we want to stop

With below code once the maxCount is reached it will stop iterating in the for loop. 


public struct UserIdSequenceGenerator: Sequence {

    private var startId: Int

    private var maxCount: Int

    private var isMaxIdReached = false

    public init(startId: Int, maxCount: Int){

        self.startId = startId

        self.maxCount = startId + maxCount

    }


}    


extension UserIdSequenceGenerator: IteratorProtocol {

    public mutating func next() -> Int? {

        defer {

            startId += 1

            if startId > maxCount {

                isMaxIdReached = true

            }

        }

        return isMaxIdReached ? nil : startId

    }

}


With the above functionality the for loop won't iterate to an infinite loop. It will print values from 10, 11, ... till 15. 


var sequence = UserIdSequenceGenerator(startId: 10, maxCount: 5)


for userId in sequence {

    print("User Id \(userId)")

}


It helps to achieve the mission to get values from 10 to 15 and we don't need a specific break condition here.



Now if you comment the for loop and use a while loop with a next method, it will still print the value's from 10 to 15. But, the Sequence now becomes destructive as as the value of isMaxIdReached will be true.


// Will print the User Id's as the Sequence is not destructed

while let uId = sequence.next() {

    print("User Id Seq 1 = \(uId)")

}


// Will not print any User Id as the Sequence is destroyed with the condition in the next() implementation. it's true now and will return nil , as we have executed the while loop once just above this current while loop

while let uId = sequence.next() {

    print("User Id Seq 2 = \(uId)")

}


The result of this would be if you iterate for the second time, since the sequence is destructed it would not print any thing


Also, if we use contains after this to find whether the sequence contains the value , it will return false too.


print("Sequence Contains 12=> \(sequence.contains(12))")


The output of this after execution of the while block will be false. 


Which is why we say Sequence Type is destructive, as UserSequenceIdGenerator sequence is destroyed with the implementation of isMaxIdReached check in next().


So we should not assume with Sequence that multiple looping on a sequence will either resume iteration or restart from the beginning.







Comments

Popular posts from this blog

hitTest on iOS to identify the view being hit

CMTimeMakeWithSeconds explained

Custom Editing Control for UITableViewCell , like iPhone Mail Appliation