Reputation: 8819
I am getting the compiler error:
Binary operator '===' cannot be applied to two 'T' operands
where T is a generic type and I am just comparing two items of type T.
So I presume I need to tell it that the ===
operator can be used on T by making T extend a protocol. If it was ==
I would use Equatable
, but I can't see what I am supposed to use for the identity comparison.
Or is there a work-around?
EDIT:
Here is a sample bit of code illustrating the problem. I have added here 'AnyObject' which causes a compilation error when the class is instantiated. If the 'AnyObject' is removed, it causes an error on the '==='.
import Foundation
protocol Messenger : AnyObject {
func notify();
}
class PostOffice<T : AnyObject> {
var messengers : [T] = []
func addMessenger(messenger : T) {
messengers.append(messenger)
}
func deleteMessenger(messenger : T) {
for i in 0 ..< messengers.count {
if messengers[i] === messenger { // error if AnyObject not used
messengers.removeAtIndex(i)
return
}
}
}
func handleDelivery(messenger : T) {} // to be overridden
func deliver() {
for messenger in messengers {
handleDelivery(messenger)
}
}
}
let p : PostOffice<Messenger> = PostOffice<Messenger>() // error if AnyObject used
The error in this case is:
Using 'Messenger' as a concrete type conforming to 'AnyObject' is not support.
Upvotes: 2
Views: 111
Reputation: 299275
You're mixing generics and protocols in a way that doesn't make sense.
class PostOffice<T : AnyObject> {
This means that you want PostOffices to be wrappers around some specific type. Not "any type that conforms to such and such protocol," but one, and exactly one, type. OK, that's fine.
let p : PostOffice<Messenger> = PostOffice<Messenger>() // error if AnyObject used
This says you want p
to be a PostOffice
that wraps any type that happens to conform to Messenger
. Well, that's not what you said you wanted PostOffice
to be. You said you wanted it to be type-specialized. So which is it?
Based on your naming, I'm assuming you really want PostOffice
to accept any Messenger
. That's fine, but then it shouldn't be generic:
class PostOffice {
var messengers : [Messenger] = []
func addMessenger(messenger : Messenger) {
messengers.append(messenger)
}
func deleteMessenger(messenger : Messenger) {
for i in 0 ..< messengers.count {
if messengers[i] === messenger { // error if AnyObject not used
messengers.removeAtIndex(i)
return
}
}
}
func handleDelivery(messenger : Messenger) {} // to be overridden
func deliver() {
for messenger in messengers {
handleDelivery(messenger)
}
}
}
That said, you're not using notify()
anywhere, which sounds like you actually want PostOffice
to work on non-Messengers. (Not sure how that's useful, but it seems to be what you wrote). That's fine, too, but then you need to some actual type (not a protocol) that you specialize PostOffice
with:
class SomeMessenger: Messenger {
func notify() {}
}
let p = PostOffice<SomeMessenger>()
If you really mean that PostOffice
should be specialized, but you want in this case to accept any kind of Messenger
, then you need type-erasure so that you can create a concrete type that wraps Messenger
:
final class AnyMessager: Messenger {
let _notify: () -> Void
init(messenger: Messenger) {
_notify = messenger.notify
}
func notify() { _notify() }
}
let p = PostOffice<AnyMessager>()
(This is the solution to many Swift protocol issues, but it doesn't feel right in this case. I suspect you really wanted PostOffice
to require a Messenger
. But I don't really understand your PostOffice
type. It mixes generics with abstract classes, which doesn't really feel very Swifty. I suspect you really want to redesign these types.)
You may be interested in this implementation of an Observable. It shows a different way to register and remove listeners without requiring ===
or a notify
method.
Upvotes: 1
Reputation: 22939
If you take a look at the ways ===
is defined:
public func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool
and
public func ===<L : AnyCollectionType, R : AnyCollectionType>(lhs: L, rhs: R) -> Bool
You can see you need ensure T
conforms to either AnyObject
or AnyCollectionType
. For example:
func f<T : AnyObject>(a: T, b: T) -> Bool {
return a === b
}
or
func f<T : AnyCollectionType>(a: T, b: T) -> Bool {
return a === b
}
Upvotes: 2