Reputation: 1211
I'm having trouble understanding why typealiasing a tuple of a generic protocol suddenly allows me to treat it as a non-generic protocol. Because of the way Swift generics work, we expect the errors we get in Examples 1, 3, 4 and 5. But why does Example 2 work? And how is it semantically different from Example 3?
As expected, this won't compile:
let foo: Hashable = "a" // error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
Because Hashable
inherits the Self
requirement from Equatable
.
But if I define a tuple of Hashable
, it works!
typealias CompositeHashable = (Hashable, Hashable)
let foo: CompositeHashable = (1, "a") // This works!
Now I no longer need to use Hashable
as a generic constraint.
I can even use CompositeHashable
in a collection:
let bar: [CompositeHashable] = [(1, "a"), ("b", "a")] // This works!
Interestingly, if I don't typealias the tuple, it doens't work.
let foo: (Hashable, Hashable) = (1, "a") // error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
That should have been equivalent to Example 2, right?
Additionally, a 1-tuple doesn't work either, with or without typealias:
typealias HashableTuple = (Hashable)
let foo: HashableTuple = ("a") // error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
One more piece to this.. if I take the previous typealias CompositeHashable
from Example 2, and simply move it into a struct, it now gives the same error we expected in the other cases.
struct CompositeKey {
typealias CompositeHashable = (Hashable, Hashable) // error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
}
Can anyone explain what's going on here?
Upvotes: 3
Views: 1267
Reputation: 17534
typealias CompositeHashable = (Hashable, Hashable)
CompositeHashable.self
// it is OK !!!!!
let foo: CompositeHashable = (1, "a") // This works!
foo.0.dynamicType // Int.Type
foo.1.dynamicType // String.Type
foo.dynamicType // (Hashable, Hashable).Type
Any.self // protocol<>.Protocol
let bar: [CompositeHashable] = [(1, "a"), ("b", "a")]
bar.dynamicType // Array<(Hashable, Hashable)>.Type Hashable.self // error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
.... this one is interesting
let foo: HashableTuple = ("a")
Void is a typealias for the empty tuple type, (). If there is only one element inside the parentheses, the type is simply the type of that element. For example, the type of (Int) is Int, not (Int). As a result, you can name a tuple element only when the tuple type has two or more elements.
this is equivalent of your typealias
let (a,b) = ("a",1)
typealias Htuple = (A:Hashable,B:Hashable)
let t:Htuple = (a,b)
Upvotes: 0