Swift: What is the difference between a typealias and an associatedtype with a value in a protocol?
Asked Answered
F

2

10

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.

February answered 10/4, 2019 at 22:26 Comment(0)
C
9

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...

  1. Hacking With Swift
  2. Medium
Consequently answered 10/4, 2019 at 22:58 Comment(1)
I know how to use associated types for the conventional purposes, but I’m wondering what the difference is in this particular case. I was surprised that you can even assign an associatedtype to a value because that seems so unlike what an associated type should do. There must be some difference between P1 and P2 because only P1 carries the usual restrictions upon protocols with associated types. I’m wondering if there are any other differences — such as how protocol methods are dispatched or something.February
H
0

It's basically the same, the main difference is that you don't have to specify the type, as the code below. But it's a problem related to Swift 2.2, when typealias became deprecated in protocols.

protocol P1 {
    associatedtype T = Int
    func anyMethod(value: T) -> T
}

struct A: P1 {
    func anyMethod(value: P1.T) -> P1.T {
        1000 + value
    }
}

More information here

Hayman answered 11/5, 2022 at 17:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.