How to Store and Call Any Object Conforming to a Protocol with an Associated Type

I am pretty new to Swift, so I'm sure there is a clear way to do this that I'm missing. I have a generic LinkedListNode type that is then managed by a class MyLinkedList, which calls into another handler MyHandler. How can I define a Handler protocol such that MyLinkedList can take any handler conforming to the protocol? This is what I've got:

public class LinkedListNode<T> {
    var value: T
    var next: LinkedListNode?
    weak var previous: LinkedListNode?

    public init(value: T) {
        self.value = value
    }
}

protocol Handler {
    associatedtype S
    func handle(last: LinkedListNode<S>)
}

struct MyHandler<T: Encodable>: Handler {
    
    func handle(last: LinkedListNode<T>) {
        print(last)
        // TODO: Iterate through the linked list and encode the elements
    }
}
class MyLinkedList<U> {
    public typealias Node = LinkedListNode<U>
    private var _count: Int = 0
    public var head: Node?
    public var last: Node?
    private let handler: Handler // Error: Handler can only be used as a generic constraints becasue it has associated type requirements
    
    init(handler: Handler) { // Error: Handler can only be used as a generic constraints becasue it has associated type requirements
        self.handler = handler
    }
    
    func handleSomeStuff() {
        self.handler.handle(last: self.last!) // Error: Member handle can not be used on value of protocol type 'Handler'
    }
}

The trick is that I not only need T == S in my struct MyHandler, which conforms to Handler, but I also need a class MyLinkedList that can can store and call any object that conforms to Handler. In practice, all of these generic types are the same type: S == T == U.

Ah, thank you. H: Handler> where H.S == U is what I was missing.

Naturally, in practice MyHandler has a lot of long-lived state and complexity I left out of the minimal example that warrants an object rather than a callback function.

Since you’re using == constraint with free variable on one side, you can also substitute the values:


class MyLinkedList<H: Handler> {
  typealias U = H.S
  ...
}

It may also be better to make Handler be agnostic from the concrete type LinkedList. Though it is understandably tricky since linked-list doesn’t really llay nice with Collection protocol, and you seem to need at least BidirectionalCollection to boot.

If Handler has only single method, consider replacing it with a closure:

class MyLinkedList<U> {
    public typealias Node = LinkedListNode<U>
    public typealias Handler = (Node) -> Void
    private var _count: Int = 0
    public var head: Node?
    public var last: Node?
    private let handler: Handler
    
    init(handler: Handler) {
        self.handler = handler
    }
    
    func handleSomeStuff() {
        self.handler(self.last!)
    }
}