Search code examples
swiftswift-protocolsswift-optionals

I expected the system to report non protocol conformance, but it does not! Why?


I am using Xcode Version 11.3.1 (11C504)

I am trying to create a generic function in Swift that will reject its parameter unless such a parameter is Optional.

In the following code, I was expecting the system to report errors in all calls to onlyCallableByAnOptable() made inside test(), because none of them provide an optional value as a parameter.

However, the system only reports non-protocol conformance if I remove the Optional extension that conforms to Optable!

Which to me, it means that the system is regarding any and all values as Optional, regardless!

Am I doing something wrong?

(By the way, the following code used to be working as expected in earlier versions of Swift. I just recently found out that it stopped working, for it was letting a non-Optional go through.)

protocol Optable {
    func opt()
}

func onlyCallableByAnOptable<T>( _ value: T) -> T where T: Optable {
    return value
}

// Comment the following line to get the errors 
extension Optional: Optable { func opt() {} }


class TestOptable {
    static func test() 
    {
        let c = UIColor.blue
        let s = "hi"
        let i = Int(1)

        if let o = onlyCallableByAnOptable(c) { print("color \(o)") }
        //^ expected ERROR: Argument type 'UIColor' does not conform to expected type 'Optable'

        if let o = onlyCallableByAnOptable(s) { print("string \(o)") }
        //^ expected ERROR: Argument type 'String' does not conform to expected type 'Optable'

        if let o = onlyCallableByAnOptable(i) { print("integer \(o)") }
        //^ expected ERROR: Argument type 'Int' does not conform to expected type 'Optable'
    }
}

Solution

  • Since you've made all Optionals conform to Optable and you are using the if let syntax to unwrap the result of the call to onlyCallableByAnOptable (which means the return type must be some kind of Optional, which means the parameter must also be that same type of Optional because both the parameter and the return type are of type T in your generic method), Swift is inferring the types being passed in as UIColor?, String?, and Int? (implicitly wrapping them in Optionals) instead of UIColor, String and Int.