I stumbled across a confusing behavior of Swift that seems to be intentional:
let x: some Equatable = "this is clearly a string"
x is CGColor // true 🤔
I wrote that this seems to be intentional because the compiler shows this warning:
'is' test is always true because 'CGColor' is a Core Foundation type
Why is that? Where does this behavior come?
This even caused a crash in my code where a switch over a generic type that might or might not represent a CGColor
, NSColor
, SwiftUI.Color
, or something else entirely matched CGColor
and accessing its alpha
property caused a crash when the value was either an NSColor
or SwiftUI.Color
. Interestingly, the same code does not crash in a playground, but still matches CGColor
when passing in an NSColor
. A SwiftUI.Color
works fine in the playground, though:
struct Box<Value: Equatable> {
var value: Value
func printAlpha() {
switch self.value {
case let color as CGColor:
print("CGColor alpha: \(color.alpha)")
case let color as NSColor:
print("NSColor alpha: \(color.alphaComponent)")
case let color as SwiftUI.Color:
print("SwiftUI.Color alpha: \(color.cgColor!.alpha)")
default:
print("not a color")
}
}
}
let nsColorBox = Box(value: NSColor.black)
nsColorBox.printAlpha() // CGColor alpha: 1.0 ❌
let swiftUIColorBox = Box(value: SwiftUI.Color.black)
swiftUIColorBox.printAlpha() // SwiftUI.Color alpha: 1.0 âś…
let cgColorBox = Box(value: CGColor.black)
cgColorBox.printAlpha() // CGColor alpha: 1.0 âś…
Here’s a screenshot of the crash in my app (not a playground). value
here is an NSColor
or SwiftUI.Color
, but you can clearly see that the CGColor
case is matched and that CGColorGetAlpha
is being called, which unsurprisingly doesn’t work:
Note that this crash is easily fixed by moving the
case let color as NSColor
above the corresponding CGColor
case 