Search code examples
arraysswiftgenericsswift-protocolsswift4.1

Adopt a protocol for Array and Dictionary


I have the following protocol:

protocol MyProtocol {

    var stringValue: String { get }
}

I also implemented it's methods for some classes and structures in extensions:

extension Int: MyProtocol {

    var stringValue: String {

        return "IntValue"
    }
}

extension String: MyProtocol {

    var stringValue: String {

        return "StringValue"
    }
}

extension Array: MyProtocol where Element == Dictionary<String, Any> {

    var stringValue: String {

        return "ArrayValue"
    }
}

extension Dictionary: MyProtocol where Key == String, Value == Any {

    var stringValue: String {

        return "DictionaryValue"
    }
}

When I tried to test it with the following code:

let dict = [["key":"value"]]
let stringValueResult = dict.stringValue
print(stringValueResult)

I received an error with text "[[String : String]] is not convertible to Array<Dictionary<String, Any>>". However my code works fine when I set type of the variable dict like that:

let dict: Array<Dictionary<String, Any>> = [["key":"value"]]

Can someone explain me why the first version of my code is not compiling?


Solution

  • The reason for this error is the conflict between the dict type inferred by the compiler and the one you mentioned while conforming Array to your protocol.

    When you write this line

    let dict = [["key":"value"]]  
    

    For compiler it will become as below where type is Array<Dictionary<String, String>>

    let dict: Array<Dictionary<String, String>> = [["key":"value"]]
    

    Now when you are doing dict.stringValue, compiler will first match the type of the calling object i.e dict with the type you defined during conformance of Array with MyProtocol

    As the compiler inferred type i.e, Array<Dictionary<String, String>> is different than the type you mentioned in conformance i.e, Array<Dictionary<String, Any>> so compiler throws error.

    But when you declare dict variable with explicit type i.e, Array<Dictionary<String, Any>> same as you defined in conformance of MyProtocol then compiler does not see any issue and your code works just fine.

    While conforming Array/Dictionary to MyProtocol you can just ignore setting the Element type as below,

    extension Array: MyProtocol {
    
        var stringValue: String {
    
            return "ArrayValue"
        }
    }
    
    extension Dictionary: MyProtocol {
    
        var stringValue: String {
    
            return "DictionaryValue"
        }
    }