Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does an optional in fast enumeration cause an infinite loop?

Tags:

swift

Evaluating the following code, I would expect a single printing of Hello World. Instead, it causes an infinite loop. Can someone explain why?

let array = ["what"] for text: String? in array {     print("Hello World") } 

(Removing the optional ? obviously makes it print only once)

like image 504
Kenneth Avatar asked Jan 03 '21 19:01

Kenneth


People also ask

How do you stop an infinite loop in Ruby?

This means that the loop will run forever ( infinite loop ). To stop this, we can use break and we have used it. if a == "n" -> break : If a user enters n ( n for no ), then the loop will stop there. Any other statement of the loop will not be further executed.

What is fast enumeration in Swift?

Fast enumeration is a language feature that allows you to efficiently and safely enumerate over the contents of a collection using a concise syntax.


1 Answers

This is an unexpected result, but it is happening because of the way Swift for in loops work under the hood.

for in takes a variable and a Sequence. Swift calls makeIterator() on the Sequence to get an IteratorProtocol which returns successive items when next() is called on the iterator. next() returns an Optional so that it can return nil when all of the items have been exhausted.

In a normal case, you receive the non-optional values and Swift continues giving them out until nil is received in which case the loop ends.

This is the equivalent of your code when you don't use an optional:

let array = ["what"] var iter = array.makeIterator() while let text = iter.next() {     print("Hello World") } 

The optional binding (while let) fails when iter.next() returns nil and the loop ends.

In your case, you have said that you will explicitly receive nil values (by declaring your loop variable as an optional), so when next() is called on the iterator and it is out of values, it hands you a nil which you graciously receive and the loop continues. The iterator continues to hand out nil and you continue to take them, and you have an infinite loop.

This is the equivalent of your code when you use an optional:

let array = ["what"] var iter = array.makeIterator() while let text: String? = iter.next() {     print("Hello World") } 

In this case, the optional binding always works because text can receive the nil.

This blog gives a nice detailed explanation of what is happening under the hood with Swift for in loops.

like image 81
vacawama Avatar answered Oct 16 '22 06:10

vacawama