In Swift, the following code compiles without issue.
protocol P1 {
associatedtype T = Int
}
protocol P2 {
typealias T = Int
}
To me, these appear to behave almost identically. The only difference I have noticed is that there are additional restrictions on when you can use P1
because it has an associated type. In particular, let x: P1
is an error while let x: P2
is fine.
What is the actual difference between these two protocols? Are they treated differently in compiled code? Lastly, is there ever an advantage to using P1
rather than P2
?
Edit for clarity:
I know the working difference between associated types and type aliases, so I am surprised that you are even allowed to give an associated type a fixed value. That seems to defeat the entire purpose of an associated type. I am wondering if there is any utility to giving an associated type a fixed value, and I am wondering if these two protocols are different once compiled.
In Swift, typealias is a function that gives a new name, or an alias, to an existing type. This type can be a concrete type, like Double or a custom structure, a compound type, like tuples, or a complex closure type.
An associated type gives a placeholder name to a type that's used as part of the protocol. The actual type to use for that associated type isn't specified until the protocol is adopted. Associated types are specified with the associatedtype keyword.
A type alias allows you to provide a new name for an existing data type into your program. After a type alias is declared, the aliased name can be used instead of the existing type throughout the program. Type alias do not create new types. They simply provide a new name to an existing type.
A Self requirement is a placeholder in a protocol for a type, used as part of the protocol, which is replaced by the concrete type that conforms to the protocol. A Self requirement can thus be thought of as a special case of an associated type.
In the code you have written there isn't really a functional difference because you have set the associatedtype
as Int
.
To get more powerful usage out of them you can use the associatedtype
as a pseudo generic constraint.
So you might write it like this...
protocol P1 {
associatedtype Item: Equatable
var itemArray: [Item] { get set }
mutating func add(item: Item)
}
extension P1 {
mutating func add(item: Item) {
itemArray.append(item)
}
}
struct StructWithStrings: P1 {
var itemArray: [String]
}
struct StructWithInts: P1 {
var itemArray: [Int]
}
Because they both conform to P1 and they both set their array type to Equatable
types. The compiler can infer the correct type of the add(item: Item)
function and help at compile time.
In contrast to this... typealias
is only really used to change the name of some type for convenience. For instance you might use a closure a lot like... (Data?, Error?, URLResponse) -> ()
and it would be long to write it many times but also loses some of the meaning. So you could do...
typealias DownloadResponse = (Data?, Error?, URLResponse) -> ()
and replace all the usages with DownloadResponse
.
There are loads of excellent resources about associatedtype
in Swift...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With