Robert Robert - 2 months ago 17
Swift Question

How to constrain a generic sequence parameter to a tuple in Swift 3?

In Swift 2, I was able to write a function which operated on any sequence of, for example,

(String, Int)
. It looked something like this:

func test<T: SequenceType where T.Generator.Element == (String, Int)>(input: T) {
for (k, v) in input {
print(k, "=", String(v))
}
}


Using a tuple as the constrained type was particular useful so that it could accept dictionaries, such as
[String:Int]
, as their sequence type consisted of tuples.

In Swift 3, I believe a similar function would be:

func test<T: Sequence>(input: T) where T.Iterator.Element == (String, Int) {
for (k, v) in input {
print(k, "=", String(v))
}
}


But attempting to pass in a
[String:Int]
, for example:
test(input: ["a": 1, "b": 2])
, causes the error:


Generic parameter 'T' could not be inferred


As far as I can tell, dictionaries in Swift 3 still use a (Key, Value) tuple as their iterator type, so I think this should work. In fact, if I don't use a single type as the constrained iterator type, such as
where T.Iterator.Element == String
, I can pass in something such as a
[String]
and it works correctly.

Is there something I'm missing, or might this be a regression in Swift 3?

Answer

An interesting example.

Let's check the definition of Dictionary about conforming to Sequence:

public func makeIterator() -> DictionaryIterator<Key, Value>

And then DictionaryIterator:

public mutating func next() -> (key: Key, value: Value)?

So, for Dictionary, T.Iterator.Element seems to be (key: Key, value: Value), not (Key, Value).

If you rewrite your function as:

func test<T: Sequence>(input: T) where T.Iterator.Element == (key: String, value: Int) {
    for (k, v) in input {
        print(k, "=", String(v))
    }
}

this works:

test(input: ["a": 1, "b": 2])

But this does not work:

test(input: [("a", 1),("b",2)]) //->Generic parameter 'T' could not be inferred

I'm not sure this is an intended feature or some sort of regression, or simply a bug.