xanderdunn
(Xander Dunn)
1
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.
xanderdunn
(Xander Dunn)
3
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.
Lantua
4
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!)
}
}