How to Make Protocol Associated Type Require Protocol Inheritance and Not Protocol Adoption

Protocol inheritance with associated type

Once a protocol has an associated type, that protocol can't be used as a type by itself for instance declarations-- only for generic constraints and declaring conformance.

So in this case, Swift is saying "yeah, but what is the concrete type for StartRouterProtocol's associated type?"

In this case, it's asking you to either:

  1. Use a concrete type directly, i.e. let router: MyStartViewClass with this conformance declaration, elsewhere: class MyStartViewClass: StartRouterProtocol { ... })
  2. OR, push the need for a concrete type up one layer, as a generic constraint i.e.
class MyRouterController<T: StartRouterProtocol> {
let router: T
}

This is probably not what you were hoping for, but unfortunately associated types add complexity to how you use protocols, especially if you're familiar with generics & interfaces from other languages. (i.e. Java/C# interfaces)

You can work around some aspects of associated types by using a concept called "type erasure" -- but that can cause other problems and complexity.

Here's some further reading that may help: https://medium.com/monstar-lab-bangladesh-engineering/swift-from-protocol-to-associatedtype-then-type-erasure-a4093f6a2d08

Use protocol that inherits from another protocol as an associated type

Your example is too complicated to understand. I tried to simplify it.

It compiles without errors:

protocol ProtocolA {}

protocol ProtocolB {
associatedtype SomeType
}

class SomeClass: ProtocolB {
typealias SomeType = ProtocolA
}

let object = SomeClass()

But the following example is no longer compiled:

protocol ProtocolA {}

protocol ProtocolB {
associatedtype SomeType: ProtocolA
}

class SomeClass: ProtocolB {
typealias SomeType = ProtocolA
}

The error is as follows:

error: type 'SomeClass' does not conform to protocol 'ProtocolB'

note: possibly intended match 'SomeType' (aka 'ProtocolA') does not conform to 'ProtocolA'

This is because protocols don't conform to themselves

Most likely in your case it is necessary to make the class template:

protocol ProtocolA {}

protocol ProtocolB {
associatedtype SomeType: ProtocolA
}

class SomeClass<T: ProtocolA>: ProtocolB {
typealias SomeType = T
}

extension Int: ProtocolA {}
extension Double: ProtocolA {}

let object1 = SomeClass<Int>()
let object2 = SomeClass<Double>()

Adoption of Protocol in Swift

It's because the protocol X states that someA is of type A, so in class Y, if you made someA of type B, then you couldn't assign anything of type A to it, which the protocol says that you need to be able to do.

If the protocol said that you needed a variable to hold any Car, and you had a Porsche, so you just wanted to tell your protocol conforming class that the variable could only hold a Porsche, then someone who comes along and tries to put a Mazda into your Porsche variable would encounter an issue, since the protocol says they should be able to.

Swift Self as associated type bound in protocol

Are you trying to say this?

protocol Factory {
associatedtype MyType
func new() -> MyType
}

protocol SelfFactory: Factory {
func new() -> Self
}

Protocol composition confusing

T is not a protocol. T is a concrete type that conforms to Typeable. You cannot then say that request must be "of the concrete type T and also conforms to SocketIORepresentable." What you meant is that T is a concrete type that conforms to both:

private func sendRequest<T: Typeable & SocketIORepresentable>(_ request: T, completion: @escaping (Result<T.Item, Error>) -> Void) { ... }

Typically you'd write this with a where clause instead to avoid such a large angle-bracket:

private func sendRequest<T>(_ request: T, completion: @escaping (Result<T.Item, Error>) -> Void)
where T : Typeable & SocketIORepresentable { ... }


Related Topics



Leave a reply



Submit