Search code examples
swiftgenericsassociated-types

Using a Generic Type with a Protocol and associated type?


I am trying to create a class that can be described as a) keeping a property of a certain type, say T, and keeping a property of another type that can update that same type, T. I think it is better explained through my (non working) example:

protocol Updater {
     associatedtype UpdateType
     func update(withSuccess success: ((UpdateType) -> Void)?, failure: ((NSError) -> Void)?)
}

class MyContainer<T> {
     private(set) var object: T
     private(set) var updater: Updater
}

In the above example, I want to ensure that the associatedtype of the protocol matches the generic type of myContainer

Is this possible to do in swift?

Thansk!


Solution

  • You can't have a property of type Updater. That's abstract. You need to use it to constrain a concrete type (U in this case).

    class MyContainer<T, U: Updater> where U.UpdateType == T {
        private(set) var object: T
        private(set) var updater: U
    }
    

    This approach can become tedious however. The where U.UpdateType == T clause often spreads repeatedly through code that uses MyContainer.

    Typically the solution is a type-eraser. Rather than a protocol, use a generic with closures:

    struct Updater<T> {
        var success: ((T) -> Void)?
        var failure: ((NSError) -> Void)?
    }
    
    class MyContainer<T> {
        private(set) var object: T
        private(set) var updater: Updater<T>
    }
    

    Updater of course could wrap a single update(withSuccess:withFailure:) method instead, but splitting it up this way is often much nicer in practice.