I’m noticing some strange behavior with the following code:
[0] as [AnyHashable] as? [Bool]
swift repl prints nil whereas Xcode prints [false]!
Two questions:
- How is
swift repl (5.8.1) producing a different result from Xcode (14.3.1)?
- Where is this implemented? I see
_IntegerAnyHashableBox does implicit type conversions across integer types but I don’t see anything about converting to Bool.
2 Likes
mayoff
(Rob Mayoff)
2
I think you are importing Foundation (perhaps indirectly) in your Xcode testing. You can make the REPL behave like Xcode:
; xcrun swift repl
Welcome to Apple Swift version 5.9 (swiftlang-5.9.0.128.2 clang-1500.0.40.1).
Type :help for assistance.
1> import Foundation
2> [0] as [AnyHashable] as? [Bool]
$R0: [Bool]? = 1 value {
[0] = false
}
3>
1 Like
Joe_Groff
(Joe Groff)
3
Int and Bool both bridge to NSNumber, so AnyHashable erases the distinction between them when bridging is involved.
6 Likes
Ah, I did try import Foundation but only later in the session. It seems to only use the Foundation-related stuff if I import it early.
Here’s what happens if I import it later:
1> [0] as [AnyHashable] as? [Bool]
$R0: [Bool]? = nil
2> import Foundation
3> [0] as [AnyHashable] as? [Bool]
$R1: [Bool]? = nil
Ahhh I see, the bridging is implemented here:
#if _runtime(_ObjC)
// Bridge to Objective-C and then attempt the cast from there.
// FIXME: This should also work without the Objective-C runtime.
if let value = _bridgeAnythingToObjectiveC(_box._base) as? T {
result.initialize(to: value)
return true
}
#endif
So during the as? [Bool] cast, the Swift runtime bridges the Int elements to NSNumber instances via _bridgeAnythingToObjectiveC and then converts them to Bool via as? T.