For fun, I am attempting to extend the Dictionary class to replicate Python's Counter class. I am trying to implement init
, taking a CollectionType
as the sole argument. However, Swift does not allow this because of CollectionType
's associated types. So, I am trying to write code like this:
import Foundation
// Must constrain extension with a protocol, not a class or struct
protocol SingletonIntProtocol { }
extension Int: SingletonIntProtocol { }
extension Dictionary where Value: SingletonIntProtocol { // i.e. Value == Int
init(from sequence: SequenceType where sequence.Generator.Element == Key) {
// Initialize
}
}
However, Swift does not allow this syntax in the parameter list. Is there a way to write init
so that it can take any type conforming to CollectionType
whose values are of type Key
(the name of the type used in the generic Dictionary<Key: Hashable, Value>
)? Preferably I would not be forced to write init(from sequence: [Key])
, so that I could take any CollectionType
(such as a CharacterView
, say).
You just have a syntax problem. Your basic idea seems fine. The correct syntax is:
init<Seq: SequenceType where Seq.Generator.Element == Key>(from sequence: Seq) {
The rest of this answer just explains why the syntax is this way. You don't really need to read the rest if the first part satisfies you.
The subtle difference is that you were trying to treat SequenceType where sequence.Generator.Element == Key
as a type. It's not a type; it's a type constraint. What the correct syntax means is:
There is a type
Seq
such thatSeq.Generator.Element == Key
, andsequence
must be of that type.
While that may seem to be the same thing, the difference is that Seq
is one specific type at any given time. It isn't "any type that follows this rule." It's actually one specific type. Every time you call init
with some type (say [Key]
), Swift will create an entirely new init
method in which Seq
is replaced with [Key]
. (In reality, Swift can sometimes optimize that extra method away, but in principle it exists.) That's the key point in understanding generic syntax.
Or you can just memorize where the angle-brackets go, let the compiler remind you when you mess it up, and call it day. Most people do fine without learning the type theory that underpins it.