Context
Consider this protocol and class in Swift 5.9:
protocol SpinnerHosting: AnyObject
{
var spinnerItem: SpinnerItem { get }
}
final class MyViewController: NSViewController
{
var activeChild: (NSViewController & SpinnerHosting)? = nil
func pushChild(_ incomingChild: (NSViewController & SpinnerHosting))
{
// #1
if incomingChild != activeChild {
...
}
// #2
if incomingChild != activeChild! {
...
}
}
}
Problem
At point #1, Swift throws this error:
Type 'any NSViewController & SpinnerHosting' cannot conform to 'Equatable'
At point #2 (ignore the unsafe unwrapping) it throws this one:
Binary operator '!=' cannot be applied to two 'any NSViewController & SpinnerHosting' operands
Question:
I understand why Protocols aren't Equatable. But I do NOT understand why the compiler thinks this isn't. Here, SpinnerHosting is constrained to AnyObject, which means reference types and therefore pointer-equality. But the same errors persist if I constrain the Protocol to NSViewController itself, which definitely surprises me because NSViewController is equatable.
I'm just trying to say: "Whatever NSViewController is going to occupy activeChild must have a spinnerItem property." (I realize I can do it with a subclass; that isn't my question.)
I've just seen this pattern: var foo: ([Class] & [Protocol]) in several Apple source examples and I don't see a good reason why this can't be Equatable.
activeChildshould beEquatableYou are right,
NSViewControllerinherits fromNSObjectwhich conforms toEquatable. So, every subclass ofNSViewControlleris stillEquatable.As a consequence a variable of type
NSViewController, regardless from additional conformance requirements, is stillEquatable.✅ Infact, this code compiles just fine.
❌ The problem arises when we make
aandboptional.Now we get your error
Wait, but
Swift Conditional Conformanceallows us to compare optional!https://www.swift.org/blog/conditional-conformance/
Right, you can equate 2 optionals if they hold 2 generic elements that can be equated
✅
However, it seems the Swift compiler is unable to infer
Equatableconformance whenExistential TypesandConditional Conformanceare involved.✅ You can help the Swift compiler adding an explicit casting
Now it works.
Here's another example
We can do a test replacing
OptionalwithArray(which similarly benefits ofConditional Conformance).✅ This compiles.
❌ But as we add existential types to the party, the
Conditional ConformancebreaksHope it helps.