So, can someone possibly explain why the Generic here fails? It doesn't make sense why it should, since the generic conformance should enforce this as a class.
Error occurs on Swift 5.7
protocol VirtualSimulatorDataSource: AnyObject {
func data(forCommand: any BLEReadCommand) -> Data
}
final class WeakVirtualSimulatorDataSourceRef {
weak var value: VirtualSimulatorDataSource?
init(value: any VirtualSimulatorDataSource) {
self.value = value
}
}
final class WeakRef<T: AnyObject> {
weak var value: T?
init(value: T) {
self.value = value
}
}
// WORKS
private var dataSources: [DeviceType: WeakVirtualSimulatorDataSourceRef] = [:]
// FAILS
private var dataSources: [DeviceType: WeakRef<VirtualSimulatorDataSource>] = [:]
VirtualSimulatorDataSource is not a class; it is a protocol. When used as a type, VirtualSimulatorDataSource (aka any VirtualSimulatorDataSource) is known as an existential type.
An existential type (with limited exceptions not applicable here) does not conform to any protocol, not even itself. In other words, any VirtualSimulatorDataSource does not conform to VirtualSimulatorDataSource or AnyObject.
Why don't existential types express their conformance in generics, however they can express it when used as concrete definitions.
ie.
If I alter the concrete definition like this it still works.
final class WeakVirtualSimulatorDataSourceRef {
weak var value: (any VirtualSimulatorDataSource)?
init(value: any VirtualSimulatorDataSource) {
self.value = value
}
}
Weak can only be expressed as a class type.
What this means is there's no way to enforce a weak generic as a protocol constraint.
Unless you can suggest an alternative.
In some ways, I always liked the C++ stye pure interfaces better, as they support this kind of magic.
Generally speaking, in Swift, I find myself fighting with the language more than the problem I'm trying to solve. It's a shame, Swift had such great potential.