1

I'm trying to extend Dictionary but can't reference self with a key. I'm confused as to why this is.

extension Dictionary {
    func foo() {
        var result = self["key"]
    }
}

I get this error : Type 'DictionaryIndex' does not conform to protocol 'StringLiteralConvertible'

If anyone has any insight, it would be appreciated.

Matthew Chung
  • 1,322
  • 1
  • 19
  • 31
  • 1
    This does not compile because the dictionary key is a generic type and need not be a string. And you (currently) cannot define an extension method which is restricted to certain values of the generic placeholder, compare http://stackoverflow.com/questions/24938948/array-extension-to-remove-object-by-value for the corresponding problem for Array. – Martin R Feb 28 '15 at 05:40

1 Answers1

10

Dictionary is a Generic struct. It is generic on its Key and Value. Thus in your extension you have to use Key as the type for the dictionary keys, and Value as the type for dictionary values.

The compiler is complaining because you are using the wrong type for the dictionary key extension.

Here is an example:

extension Dictionary {
    func ext(key: Key) {
        if let value = self[key] {
            // use your value
            println("Key is present")
        } else {
            println("No value for key")
        }
    }
}

let dic = ["A": 20]
dic.ext("A")
dic.ext("B")

Here is how you can do something similar ... it might make clearer why your test didn't work:

extension Dictionary {
    var foo: String? {
        if let key = "key" as? Key {
            return self[key] as? String
        }
        return nil
    }
}
let dic1 = ["A": "an A", "key": "the value"]
dic1.foo // "the value" as optional
dic.foo  // nil since dic value type is Int

Since Dictionary is a generic struct, you might reconsider extending it as if it is a specific concrete type.

Matteo Piombo
  • 6,688
  • 2
  • 25
  • 25
  • Thank you very much! When you mention the concrete type, are you referring to an object or using a generic? – Matthew Chung Feb 28 '15 at 16:05
  • @MatthewChung ups ... _reconsider_ I meant _consider not to do so_. Extending a _generic_ type with logic specific to just one specific possible concrete type case, might introduce a lot of confusion in your code base. It is not difficult to define your specific dictionary of `[String : String]`. Just name a struct containing a `var` of type `[String : String]` and define the `subscript (key: String) -> String?` to just return or set the internal var. This way there will be no confusion in your code about a strange `Dictionary` extension that works just in case of `[String : String]`. – Matteo Piombo Mar 01 '15 at 10:17
  • I like your point. I was however using this dictionary to serialize to json. Do you have a suggestion on a way to reduce the confusion while still allowing the object to serialize to json? – Matthew Chung Mar 02 '15 at 04:45
  • If you have a simple data model, just do your custom structs and json serialisation / deserialisation ... you know ... KISS principle ;-) In case of more complex data model, just look at the tones of solutions proposed from people smarter then me. [here](https://github.com/vsouza/awesome-ios?utm_campaign=iOS_Dev_Weekly_Issue_187&utm_medium=email&utm_source=iOS%2BDev%2BWeekly) you will find a few. – Matteo Piombo Mar 02 '15 at 05:53