this comes out of an @MJTsai post about pattern matching with error codes.
https://mjtsai.com/blog/2023/03/13/pattern-matching-on-swift-error-codes/
He comments that it doesn't work when codes use a protocol, and gives the following example:
setup:
protocol MyErrorProtocol<Code>: Error {
associatedtype Code: MyCodeProtocol
var code: Code { get }
}
protocol MyCodeProtocol: RawRepresentable where RawValue == Int {
}
enum MyCode: Int, MyCodeProtocol {
case a
case b
}
struct MyError: MyErrorProtocol {
let code: MyCode
}
func ~=<Code: MyCodeProtocol> (code: Code, error: any Error) -> Bool {
guard let myError = error as? any MyErrorProtocol,
let myCode = myError.code as? Code else { return false }
return myCode == code
}
the following doesn't work. The switch gives a warning
let error: Error = MyError(code: .a)
switch error {
case MyCode.a://Warning: Cast from 'any Error' to unrelated type 'MyCode' always fails
print("a" )
default:
print ("other")
}
however - writing the same logic as an if/else with the pattern matching operator does work correctly
if (MyCode.a ~= error) {
//no error - this branch is triggered
print("a" )
}
else {
print ("other")
}
what's going on?
clearly the switch isn't using the pattern match operator in the same way as the if/else code.
Any insights appreciated :)
3 Likes
meanwhile - a simple protocol case with no generics works correctly.
protocol HasString {
var string:String {get}
}
struct Foo:HasString {
var string:String
}
func ~=(match: String, input: HasString) -> Bool {
return match == input.string
}
let foo = Foo(string: "Hello")
switch foo {
case "Hello"://This works
print("match")
default:
break
}
Protocols aren't relevant; it's a problem with enumerations. I haven't seen it before.
struct S { static let instance = Self() }
enum E { case instance }
func ~= (_: S, _: Void) -> Bool { true }
func ~= (_: E, _: Void) -> Bool { true }
S.instance ~= () // compiles
if case S.instance = () { } // compiles
E.instance ~= () // compiles
if case E.instance = () { } // Cannot convert value of type '()' to specified type 'E'
Edit: Oh, interesting. I don't see how what you're trying to do can work, unless this gets fixed:
2 Likes