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 😒
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)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With