# Protocols With Associated Types

This is one of the few articles with a source. See the bottom of the page for more information.

### Fear Mongering Preface

Be warned this is one of the hardest, most frustrating, and rare Swift features (at least when using UI). This is because it flips protocols on its head and forces you to think about types differently. Not to mention it often forces either the use of enums with associated values (another advanced topic) or type erasure (a topic I have yet to understand).&#x20;

{% content-ref url="/pages/1A2kz5d27g30OnsUXZNd" %}
[Enums with Associated Values](/resources/swift-foundations/enums-and-switches/enums-with-associated-values.md)
{% endcontent-ref %}

As you will find throughout this article, this a topic even I am still trying to grasp. So, I will do my best to explain everything as well as I can, but there will be some gaps in my knowledge. In fact, there is evidence that this is an unfinished feature, so my knowledge may become outdated soon.

Okay, for those I have not scared yet, the advantage for protocols with associated types or PATs is kind of like generics with classes (just kind of). I like to think of them as abstract classes (in Java) that are generic. If you remember from the discussion of `protocol`s, our implementation of sets were limited to single types–we used integers specifically.&#x20;

### Associated Types

Let's fix this by making this parametric. Similar to generics, we need to create a name for our parametrizing type. To do this, we use the keyword `associatedType` followed by a type name, which can be constrained (more on this later). Let's call the type of our elements of our set `Element`: `associatedType Element`.

```swift
protocol Set {
    associatedtype Element
    /**
    Number of unique elements in the set
     */
    var length: Int { get }
    
    /**
    Unique elements in the set
     */
    var values: [Element] { get set }
    
    /**
    Adds `element` to the set.
     */
    mutating func add(_ element: Element)
    
    /**
    - returns:
     whether a set contains an element
     */
    func contains(_ element: Element) -> Bool
}

```

Then, when we want a type to conform or adopt our `Set` implementation, we can explicitly dictate the type with a `typealias` or be consistent with our typing.

```swift
struct IntegerSetExplicit: Set {
    typealias Element = Int
    
    var length: Int { values.count }
    
    var values = [Element]()
    
    mutating func add(_ element: Element) {
        if !contains(element) {
            values.append(element)
        }
    }
    
    func contains(_ element: Element) -> Bool {
        values.contains(element)
    }
    
    
}

struct IntegerSetImplicit: Set {
    
    var length: Int { values.count }
    
    var values = [Int]()
    
    mutating func add(_ element: Int) {
        if !contains(element) {
            values.append(element)
        }
    }
    
    func contains(_ element: Int) -> Bool {
        values.contains(element)
    }
}

```

### Generic Constraint

This seems all well and dandy... Why is this so hard?

Let's try storing it in a variable...

```swift
var mySet: Set = ...
```

Oops, that doesn't compile... Well, actually that makes sense. If we think about this as a generic, we need to specify the type. Let's fix that:

```swift
protocol IntegerSet: Set where Element == Int {}
var myIntegerSet: IntegerSet = ...
```

The same error!

In fact, when working with PATs you will see this often:

"**error: protocol '\<SomeProtocol>' can only be used as a generic constraint because it has Self or associated type requirements"**

In short, PATs **are not types**. You can only use them as constraints! This is a huge problem. Let's revisit the Swift standard library.

![](/files/JSiK1KtKGRaW7dxxHzcy)

This, funnily enough, as Gallagher points out, is actually a list of all the ways you cannot use `protocol`s with associated types.

Now you can get around some of this with Opaque typing, but that is a topic for another article, as I have yet to understand them!

So, what does this mean for us? We can't use PATs as types. We can only use them to show conformance. This means instead of using our protocol `Set` as a type we need a type that conforms to `Set`. If you have not reviewed generics and constraints, this may seem like a great sin and that Swift breaks all of your conceptions surrounding parametric polymorphism, but it doesn't. It's just annoying.

Let's say we want to write a function `concatenate` that takes in a bunch of sets and concatenates the result. If we were working with a normal protocol, we could do:

```swift
func concatenate(_ sets: [Set]) -> Set
```

But since, again, we can only use `Set` as a tool to show conformance. But, we want to keep this as widely applicable as possible. So, we use generics!

```swift
func concatenate<T: Set>(sets: [T]) -> T {
    assert(sets.count > 0)
    var base = sets[0]
    for set in sets[1..<sets.count] {
        for elt in set.values {
            base.add(elt)
        }
    }
    return base
}
```

This is basically the same, except for two differences. The less important is that we have given `Set` a new name. The more important is that all of our implementations of `Set` must be the exact same. This was not the case with normal protocols. This is where things get extra dicey.

If you want multiple implementations in the same list, there are two methods you can use. The first, which I **highly** suggest is enums with associated values–it's so OCaml and is very nice. The other is type erasure, which I sadly am not familiar with yet, so you will need to look into it yourself. But my vague understanding is that you use a wrapper type to abstract away the associated type and distill it into its barebones features to guarantee only what you need.

### Conditional Functions

We can use constraints to add functionality! We can add constraints directly to the associated type if it is part of the invariant or conditionally to certain functions.&#x20;

See constraints for more:

{% content-ref url="/pages/YMy4FafSDAqXc7MDUXww" %}
[Constraints](/resources/swift-foundations/constraints.md)
{% endcontent-ref %}

`contains` seems like something we can implement broadly. Assuming we have access to equality, we can just iterate through the values and check!&#x20;

```swift
extension Set {
    
    func contains(_ element: Element) -> Bool where Element: Equatable {
        for val in values {
            if val == element {
                return true
            }
        }
        return false
    }
    
}
```

Or, better yet, we can just Array's implementation of contains!

```swift
extension Set {
    
    func contains(_ element: Element) -> Bool where Element: Equatable {
        values.contains(element)
    }
    
}
```

For those of you that remember default implementations, this allows us to create conditional default implementations! This means that if we ever implement `Set` with a type that conforms to `Equatable`, we don't need to implement contains! Otherwise, we do.

### Credits

Most of my understanding as well as my discussion originates from the following video. It is somewhat outdated, but it is a nice narrative of why this feature is the way it is and how to use it (kind of):

{% embed url="<https://www.youtube.com/watch?v=XWoNjiSPqI8>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ios-course.cornellappdev.com/resources/swift-foundations/protocols/protocols-with-associated-types.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
