swift protocol with associated type

Viewed 148

how can I correct errors?!

domain module, contains all abstracts

//MARK: - Domain
protocol TypeB {
    associatedtype P
    func makeP() -> P
    init()
}

protocol TypeA {
    associatedtype P
    associatedtype B: TypeB
    
    func makeP() -> P
    init(objB: B)
}

protocol FirstTargetFabricType {
    func makeB<B: TypeB>() -> B where B.P == Int
}

protocol SecondTargetFabricType {
    func makeA<B, A: TypeA>(objcB: B) -> A where A.B == B, A.P == B.P, B.P == Int
}

the first module, for example the module for working with the network

//MARK: - First Target
class ClassB: TypeB {
    required init() { }
    func makeP() -> Double { return 10 }
}


// error: Cannot convert return expression of type 'ClassB' to return type 'B'
class FirstTargetFabric: FirstTargetFabricType {
    func makeB<B: TypeB>() -> B where B.P == Int {
        return ClassB()
    }
}

the second module, for example the module for working with the storage

//MARK: - SecondTarget
    class ClassA<B: TypeB>: TypeA {
        let objB: B
        
        required init(objB: B) {
            self.objB = objB
        }
        
        func makeP() -> B.P { return objB.makeP() }
    }
    
    class SecondTargetFabric: SecondTargetFabricType {
        func makeA<B, A: TypeA>(objcB: B) -> A where B == A.B, B.P == A.P, B.P == Int {
            return A(objB: objcB)
        }
    }

application target

//MARK: - app
let firstFabric: FirstTargetFabricType = FirstTargetFabric()
let secondFabric: SecondTargetFabricType = SecondTargetFabric()

/// error: Generic parameter 'A' could not be inferred
let res = secondFabric.makeA(objcB: firstFabric.makeB())

I'm trying to make a service loader for pagination. I just want to pass in the class initializer an entity that will go to the network

3 Answers

how good would that approach be?

 //MARK: - Domain
open class TypeB<T: Decodable> {
    open func makeP() -> T {
        fatalError("Required function have not been implemented")
    }
}

open class TypeA<T: Decodable> {
    open func makeP() -> T {
        fatalError("Required function have not been implemented")
    }
}

public protocol FirstTargetFabricType {
    func makeInt() -> TypeB<Int>
    func makeDouble() -> TypeB<Double>
}

public protocol SecondTargetFabricType {
    func makeInt(objInt: TypeB<Int>) -> TypeA<Int>
    func makeDouble(objDouble: TypeB<Double>) -> TypeA<Double>
}



//MARK: - First Target
internal class ClassB: TypeB<Int> {
    override func makeP() -> Int { return 10 }
}

internal class ClassBB: TypeB<Double> {
    override func makeP() -> Double { return 20 }
}

public class FirstTargetFabric: FirstTargetFabricType {
    public func makeInt() -> TypeB<Int> { ClassB() }
    public func makeDouble() -> TypeB<Double> { ClassBB() }
}



//MARK: - SecondTarget
internal class ClassA: TypeA<Int> {
    let objB: TypeB<Int>

    init(objB: TypeB<Int>) {
        self.objB = objB
    }
    
    override func makeP() -> Int {
        objB.makeP()
    }
}

internal class ClassAA: TypeA<Double> {
    let objB: TypeB<Double>

    init(objB: TypeB<Double>) {
        self.objB = objB
    }
    
    override func makeP() -> Double {
        objB.makeP()
    }
}

public class SecondTargetFabric: SecondTargetFabricType {
    public func makeInt(objInt: TypeB<Int>) -> TypeA<Int> { ClassA(objB: objInt) }
    public func makeDouble(objDouble: TypeB<Double>) -> TypeA<Double> { ClassAA(objB: objDouble) }
}


//MARK: - app
let first = FirstTargetFabric()
let second = SecondTargetFabric()

let objInt = first.makeInt()
let objDouble = first.makeDouble()


print(second.makeInt(objInt: objInt).makeP())
print(second.makeDouble(objDouble: objDouble).makeP())

This is the proper way of doing it with protocols, but that might become very complicated if you keep on going with associated protocols.

In method makeAa: you are trying to return TypeA as type A, and not all TypeA are A, so you have to return A instead

protocol TypeA {
    associatedtype P
    associatedtype B: TypeB
    
    func makeP() -> P
    init(objB: B)
}

protocol TypeB {
    associatedtype P
    func makeP() -> P
}

class ClassB: TypeB {
    func makeP() -> Int { return 10 }
}

class ClassA<B: TypeB>: TypeA {
    
    let objB: B
    
    required init(objB: B) {
        self.objB = objB
    }
    
    func makeP() -> B.P {
        return objB.makeP()
    }
}

//**Cannot convert return expression of type 'ClassA<B>' to return type 'A'**
func makeAa<B, A: TypeA>(objB: B) -> A where B.P == Int, A.P == B.P, A.B == B {
    return A(objB: objB)
}


//**Generic parameter 'A' could not be inferred**
let res: ClassA = makeAa(objB: ClassB())

For the update: Again, you have to return type B, not all ClassB are B()

// error: Cannot convert return expression of type 'ClassB' to return type 'B'
class FirstTargetFabric: FirstTargetFabricType {
    func makeB<B: TypeB>() -> B where B.P == Int {
        return B()
    }
}

Here you have to specify generic class B that you want to create (ClassB)

/// error: Generic parameter 'A' could not be inferred
let b: ClassB = firstFabric.makeB()
let res: ClassA = secondFabric.makeA(objcB: b)

And ClassB should return the same (Int) as ClassA to combine them

//MARK: - First Target
class ClassB: TypeB {
    required init() { }
    func makeP() -> Int { return 10 }
}
Related