Reputation: 11083
I was surprised that this swift code behaves nicely:
let values = ["Hello", "Test"]
var count = 0
for string: String in values {
count = count + 1
print("count is: ", count)
print(string)
}
with output of:
count is: 1
Hello
count is: 2
Test
but making the String into String? creates an infinite loop.
let values = ["Hello", "Test"]
var count = 0
for string: String? in values {
count = count + 1
print("count is: ", count)
print(string)
}
with output of:
count is: 1
Optional("Hello")
count is: 2
Optional("Test")
count is: 3
nil
count is: 4
nil
count is: 5
nil
count is: 6
nil
count is: 7
nil
count is: 8
(ad infinitum)
Swift has been so good at catching weird code problems that I was surprised I could walk into such a mess without warning or error. Is this really what one would expect from Swift 4? And if so, why?
Upvotes: 5
Views: 324
Reputation: 539945
To understand this issue it helps to recollect how for-in loops work:
for s in values {
print(s)
}
creates an iterator of the sequence, and calls the iterator's next()
method until that returns nil
:
var it = values.makeIterator()
while let s = it.next() {
print(s)
}
Your second version is equivalent to
var it = values.makeIterator()
while let s: String? = it.next() {
print(s)
}
and now the compiler warns:
warning: explicitly specified type 'String?' adds an additional level of optional to the initializer, making the optional check always succeed while let s: String? = it.next() { ^ ~~~~~~~ ~~~~~~~~~ String
So what happens here is that the String?
returned from it.next()
is wrapped into a “nested optional” .some(it.next())
of type String??
, which is then optionally bound to s: String?
.
This does always succeed, because .some(it.next())
is not String??.none
.
Therefore the loop never terminates.
One could argue that the compiler should warn as well for
for s: String? in values {
print(s)
}
Upvotes: 8
Reputation: 527
There is no error. In the first function it will keep going until it no more strings.
But other hand the second function you set the string to optional so when its no more string it will still keep going. Because nil is a nil value and it’s not the same as nothing. You have nothing that ends that loop.
Upvotes: 0
Reputation: 35
Your "for" runs on indexes. Under the index in excess of the number of elements is nill.
Upvotes: 0