Roman Podymov
Roman Podymov

Reputation: 4521

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?

Upvotes: 0

Views: 301

Answers (2)

Kamran
Kamran

Reputation: 15238

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"
    }
}

Upvotes: 0

Mukesh
Mukesh

Reputation: 2902

You should change your Array and Dictionary implementation constraint like this:

extension Array: MyProtocol where Element: MyProtocol {

    var stringValue: String {

        return "ArrayValue"
    }
}

extension Dictionary: MyProtocol where Key == String {

    var stringValue: String {

        return "DictionaryValue"
    }
}

Now if you run following code it will print: ArrayValue

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

Upvotes: 1

Related Questions