Reputation: 7555
This code works fine. It iterates my array of one Int!
and prints its magnitude.
import Foundation
let x : Int! = 1
[x].forEach {i in
print(i.magnitude)
}
Output:
1
Presumably, i
in the loop body is an Int
or an Int!
, and indeed if I ask Xcode for "quick help" on forEach
it reports:
func forEach(_ body: (Int) throws -> Void) rethrows
However, if perform two statements in my forEach
body, instead it fails to compile, complaining that I need to unwrap i
which now has the optional type Int?
.
import Foundation
let x : Int! = 1
[x].forEach {i in
print(i.magnitude)
print(i.magnitude)
}
Compile error:
Value of optional type 'Int?' must be unwrapped to refer to member 'magnitude' of wrapped base type 'Int'
And if I ask for "quick help" now I get:
func forEach(_ body: (Int?) throws -> Void) rethrows
How on earth does the number of statements I place in my loop body manage to affect the type of the loop variable?
Upvotes: 4
Views: 217
Reputation: 535547
Basically, you've elicited an edge case of an edge case. You've combined two things that are the work of the devil:
You should try to avoid both of those; your code will be cleaner and will compile a lot faster. Indeed, implicit type inference of anything other than a single literal, like a string, Int, or Double, is a huge drag on compilation times.
I won't pretend to imitate the compiler's reasoning; I'll just show you an actual solution (other than just not using an IUO in the first place):
[x].forEach {(i:Int) in
print(i.magnitude)
print(i.magnitude)
}
Our Int
type is legal because we take advantage of the single "get out of jail free" card saying that an implicitly unwrapped Optional can be used directly where the unwrapped type itself is expected. And by explicitly stating the type, we clear up the compiler's doubts.
(I say "directly" because implicit unwrappedness of an Optional is not propagated thru passing and assignment. That is why in your second example you discovered Int?
, not Int
, being passed into the closure.)
Upvotes: 3