Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift-Generics: "Cannot specialize non-generic type"

I try to implement object oriented code by using a generic protocol. Lets say I have two protocols

protocol Executable: class {
    func execute()
}

protocol Dockable: class {
    associatedtype T
    func dock(object: T)
}

I've implemented a decorator for Executable:

final class DockableExecutable: Executable, Dockable {
    typealias T = Executable
    private let decorated: Executable
    private var docked: Executable?
    init(_ decorated: Executable) {
        self.decorated = decorated
    }
    // from Executable
    func execute() {
        decorated.execute()
        docked?.execute()
    }
    // from Dockable
    func dock(object: Executable) {
        docked = object
    }
}

Now I wan't to use it in a class like that:

final class MyViewController: UIViewController {
    init(save: Executable, uiUpdateConnector: Dockable<Executable>) {}
}

But that isn't possible because the protocol itself is not generic, only the function. The compiler tells me:

Cannot specialize non-generic type 'Dockable'

The idea is to use it like that:

let dockableExecutable = DockableExecutable(
    SQLUpdateExecutable(/** dependencies **/)
)
let controller = MyViewController(save: dockableExecutable, uiUpdateConnector: dockableExecutable)

How is the correct syntax in Swift 3 to make the compiler happy?

UPDATE 1

I made some progress with following code:

final class MyViewController: UIViewController {
    init<DOCKABLE: Dockable>(save: Executable, uiUpdateConnector: DOCKABLE) where DOCKABLE.T: Executable {}
}

It looks strange, maybe someone has a better idea? When using the class now I get:

Generic parameter 'DOCKABLE' could not be inferred

So my questions hasn't changed:

How is the correct syntax in Swift 3 to make the compiler happy?

Update 2

It seems it isn't possible to use the swift generic (or better: type associated) protocols in protocol based object oriented programming.

So we have to wrap them into some kind of container and loose the protocol based approach or we have to define different protocols for each situation.

Because working without protocols is no option for me, I have to write different protocols without generics. Shame on swift 😒

like image 991
ObjectAlchemist Avatar asked Dec 06 '25 01:12

ObjectAlchemist


2 Answers

I'm not sure that your problem can be solved without type erasure, because you cannot use protocols with associated types for types of variables or parameters of functions.

Try the solution with type erasure:

final class AnyDockable<U>: Dockable {
    typealias T = U

    let _dock: (U) -> Void
    let _execute: () -> Void

    init<Base: Dockable & Executable>(base: Base) where Base.T == U {
        _dock = base.dock
        _execute = base.execute
    }

    func dock(object: U) {
        _dock(object)
    }

    func execute() {
        _execute()
    }
}

Your compiler will be happy, I've checked it:

class Exe: Executable {
    func execute() {
        print("")
    }
}
let executable: Executable = Exe()

let de = AnyDockable(base: DockableExecutable(executable))

final class MyViewController: UIViewController {

    init(save: Executable, uiUpdateConnector: AnyDockable<Executable>) {
        super.init(nibName: "", bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

MyViewController(save: executable, uiUpdateConnector: de)
like image 120
ixrevo Avatar answered Dec 07 '25 15:12

ixrevo


If I am not mistaken you are looking for Protocol Composition (multi-protocol conformance), no? You could then use different of your decorators afterwards.

Maybe you are looking for this: Swift 3 protocol<A, B>, and in Swift 4 A & B:

final class MyViewController: UIViewController {
    init(save: Executable, uiUpdateConnector: protocol<Dockable, Executable>) {}
}

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

http://braking.github.io/require-conformance-to-multiple-protocols/

Multiple Type Constraints in Swift

like image 45
smat88dd Avatar answered Dec 07 '25 15:12

smat88dd



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!