Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Constrained extension on Dictionary by Element

Tags:

ios

swift

I want to create an extension on Dictionary that only affects dictionaries with type [String:AnyObject], which is the data type returned from parsed JSON dictionaries. Here's how I set it up:

typealias JSONDictionary = [String : AnyObject]
extension Dictionary where Element:JSONDictionary {
    // Some extra methods that are only valid for this type of dictionary.
}

Xcode is generating an error on Element, saying it's an undeclared type. However, the first line of the definition of Dictionary is a typealias declaring Element. What am I doing wrong here?

like image 752
Josh at The Nerdery Avatar asked Dec 25 '22 16:12

Josh at The Nerdery


1 Answers

Element is a tuple:

typealias Element = (Key, Value)

That cannot match the type you're trying to compare it to (a Dictionary). You can't even say something like where Element:(String, AnyObject) because tuples don't subtype that way. For example, consider:

var x: (CustomStringConvertible, CustomStringConvertible) = (1,1)
var y: (Int, Int) = (1,1)
x = y // Cannot express tuple conversion '(Int, Int)' to ('CustomStringConvertible', 'CustomStringConvertible')

Compare:

var x1:CustomStringConvertible = 1
var y1:Int = 1
x1 = y1 // No problem

I suspect you get "undeclared type" is because Element is no longer an unbound type parameter, it's a bound type parameter. Dictionary is conforming to SequenceType here. So you can't parameterize on it (at least not in one step; you have to chase it through another layer of type parameters to discover it's "ultimately" unbound). That seems a bad error message, but I suspect it bubbles out of "undeclared type out of the list of types that could possibly be used here." I think that's worth opening a radar on for a better error message.

Instead, I think you mean this:

extension Dictionary where Key: String, Value: AnyObject { }

EDIT for Swift 2:

This is no longer legal Swift. You can only constrain based on protocols. The equivalent code would be:

protocol JSONKey {
    func toString() -> String
}
extension String: JSONKey {
    func toString() -> String { return self }
}

extension Dictionary where Key: JSONKey, Value: AnyObject { ... }
like image 103
Rob Napier Avatar answered Jan 15 '23 23:01

Rob Napier