How the abstract type of the protocol is associated with the abstract type in the class

foundation

(Stellar) #1
protocol Merger {
    associatedtype Element
    func merge(_ a:Element, _ b:Element) -> Element
}

class AbstractTest<M:Merger, E> {
    typealias Element = E
    
    var a, b:E
    var merger:M
    init(merger:M, a:E, b:E) {
        self.merger = merger
        self.a = a
        self.b = b
    }
    
    func test() -> E {
        return self.merger.merge(a, b)
    }
}

error: Cannot invoke 'merge' with an argument list of type '(E, E)'

I expect to abstract a Merger protocol for external calls. How do I use swift to implement it?


(Lukas Stabe 🙃) #2

The typealias Element = E creates a new typealias on the class AbstractTest, which does not influence the associated types of M. Instead, you should add a generic where clause to require M.Element == E.


#3

Did you mean something like this?

class AbstractTest<M:Merger> {
    var a, b: M.Element
    var merger: M
    
    init(merger: M, a: M.Element, b: M.Element) {
        self.merger = merger
        self.a = a
        self.b = b
    }
    
    func test() -> M.Element {
        return merger.merge(a, b)
    }
}

(Stellar) #4

I want to implement a segment tree, your method solves this problem, tks.

class SegmentTree<M:Merger>: NSObject {
    var merger:M
    var tree:Array<M.Element>
    private var data: Array<M.Element>
    init(arr: Array<M.Element>, merger:M) {
        self.merger = merger
        self.data = Array.init(arr)
        self.tree = Array.init()
        super.init()
        
        self.buildSegmentTree(treeIndex: 0, l: 0, r: self.data.count - 1)
    }

    func buildSegmentTree(treeIndex:Int, l:Int, r:Int) {
        if l == r {
            tree[treeIndex] = data[l]
            return;
        }

        let leftIndex = leftChild(treeIndex)
        let rightIndex = rightChild(treeIndex)

        let mid = l + (r - l) / 2
        //left = [l..mid]  right = [mid+1 .. r]
        buildSegmentTree(treeIndex: leftIndex, l: l, r: mid)
        buildSegmentTree(treeIndex: rightIndex, l: mid + 1, r: r)

        tree[treeIndex] = merger.merge(tree[leftIndex] , tree[rightIndex])
    }
}

(Stellar) #5
class AbstractTest<M:Merger, E> where M.Element == E {}

Your method can solve this problem, tks~