Subprotocol as associated type?

I want to define a protocol and some classes like this:

protocol AppleDevices {
    associatedtype DelegateProtocol: AppleDevicesDelegate
    var delegate: DelegateProtocol! { get }
    init(delegate: DelegateProtocol)
}

protocol AppleDevicesDelegate { ... }

class IPhone: AppleDevices { 
    weak var delegate: IPhoneDelegate! // instead of AppleDeviceDelegate where someone could accidentally assign say, MacDelegate to this class
    init(delegate: IPhoneDelegate) { ... }
}

protocol IPhoneDelegate: AppleDevicesDelegate { … }

The compiler complains that the class IPhone does not conform to its protocol because, to my understanding, the associatedtype of a protocol implementation cannot be a subprotocol of some other protocol. As in, the above code works if IPhoneDelegate was a class, not another protocol.

As far as I understand it, the design I would like to achieve above is not currently possible in the Swift compiler.

1 Like

You can not use an existential as a type conforming to that protocol. If you change the class to be generic over an AppleDevicesDelegate it would work because you're now using a concrete type.

class IPhone<Delegate: IPhoneDelegate>: AppleDevices {
  weak var delegate: Delegate!
}

That would work.

1 Like

Putting an explicit typealias for the associated type (rather than leaving it to be inferred from the parameter of the init) gives a better error message:

class IPhone: AppleDevices { 
    // ❌ possibly intended match 'IPhone.DelegateProtocol' (aka 'any IPhoneDelegate')
    // does not conform to 'AppleDevicesDelegate'
    typealias DelegateProtocol = any IPhoneDelegate

    weak var delegate: IPhoneDelegate!
    init(delegate: IPhoneDelegate) {  }
}

I still don't quite understand why it doesn't conform. Can someone please elaborate?