Swift-Generics: "Cannot Specialize Custom Type"

I am trying to implement object oriented code using a common protocol. Let's say I have two protocols.

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

I implemented a decorator for the 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 will not use it in this class:

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

But this is impossible, because the protocol itself is not general, but only a function. The compiler tells me:

Unable to specialize non-standard type "Dockable"

The idea is to use it like this:

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

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

UPDATE 1

I made some progress with the following code:

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

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

The general DOCKABLE parameter cannot be output.

So my questions have not changed:

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

Update 2

It seems impossible to use fast generic (or better: type-related) protocols in protocol-based object-oriented programming.

Therefore, we must wrap them in some kind of container and lose the protocol-based approach, or we need to define different protocols for each situation.

Since working without protocols is not an option for me, I have to write different protocols without generics. Shame on a quick πŸ˜’

+5
source share
2 answers

I'm not sure that your problem can be solved without type erasure, because you cannot use protocols with related types for variable types or function parameters.

Try an erasure solution like:

 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 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) 
+1
source

If I’m not mistaken, you are looking for the composition of the protocol (the correspondence of several protocols), no? Then you can use different decorators.

You may be looking for: 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.imtqy.com/require-conformance-to-multiple-protocols/

Multiple type restrictions in Swift

0
source

Source: https://habr.com/ru/post/1265679/


All Articles