Associated Types in Swift

Context

When working on Swift protocols, you might need to use generic types as a variable. Swift compiler can understand when you provide a protocol as a variable, but what if you want to use a type? Here is an example of implementing a data structure based on protocols.

protocol A {

}

protocol B {
    var a: A { get }
}

struct myStructA: A {

}

struct myStructB: B {
    var a: myStructA
}

By using myStructA for the variable a Xcode will complain because myStructB doesn’t conform to protocol B. The reason is that Swift compiler is expecting a type A and can’t figure that myStructA is conforming to A. A solution would be to change the type of a in myStructB to A, but then what if you want to use myStructA and use custom features that you didn’t declare in protocol A?

That’s where associated types become handy.

Unlike classes, structs and enums, protocols don’t support generic type parameters but abstract type members. In Swift they are known as associated types.

Cf Apple:

“When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name (or alias) to a type that is used as part of the protocol. The actual type to use for that associated type is not specified until the protocol is adopted. Associated types are specified with the typealias keyword.”

That said, let’s refactor our previous example using an associated type.

protocol A {

}

protocol B {
    associatedtype AType: A
    var a: AType { get }
}

struct myStructA: A {

}

struct myStructB: B {
    typealias AType = myStructA
    var a: AType
}

By defining an associated type over protocol A we are able to specify to the compiler a placeholder for the type. It is in the protocol implementation that we specify the final type, which gives us the possibility to manipulate a struct object. If your myStructA object contains extra features than what is available in protocol A you will be able to access them.

You will notice that as soon as you start using associated types in a protocol, you have to use Swift generics everywhere.

This implementation will not compile anymore:

func myFunc(b: B) {

}

You have to use Swift generics:

func myFunc<T: B>(b: T) {

}

Because you specified an associated type, that type is not specific enough to be used as a proper type. You have to use the generic syntax to tell the compiler what type is expected in your function.

Conclusion

Currently associated types are your only option if you have generic types in your protocols and you want to use an implementation. They are very easy to use and will give you the flexibility to write powerful and cleaner code.

Categories: