2

I'm trying to build a simple observer mixin with Swift 2. Here comes just the relevant part.

protocol Observable{

    typealias T 
    var observers:[T] { get set }
    mutating func removeObserver(observer:T)
}

To create the mixin I use an extension:

extension Observable{

    mutating func removeObserver(observer:T){
        let index = self.observers.indexOf{ $0 === observer }
        if let _ = index{
            self.observers.removeAtIndex(index)
        }
    }   
}

This creates the compiler error: Binary operator '===' cannot be applied to operands of type '_' and 'Self.T'

Can you explain to me why this error is occurring?

hendra
  • 2,531
  • 5
  • 22
  • 34

1 Answers1

2

The "identical-to" operator === can only be applied to reference types, i.e. instances of a class. One possible solution is to restrict the generic type T to AnyObject (the protocol to which all classes implicitly conform):

protocol Observable {

    typealias T : AnyObject
    var observers:[T] { get set }
    mutating func removeObserver(observer:T)
}

extension Observable {

     mutating func removeObserver(observer:T) { 
        if let index = (self.observers.indexOf { $0 === observer }) {
            self.observers.removeAtIndex(index)
        }
    }   
}

Alternatively, restrict T to Equatable types (which means that a == operator must be defined for the type):

protocol Observable {

    typealias T : Equatable
    var observers:[T] { get set }
    mutating func removeObserver(observer:T)
}

extension Observable {

     mutating func removeObserver(observer:T) { 
        if let index = self.observers.indexOf(observer) {
            self.observers.removeAtIndex(index)
        }
    }   
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Thanks for the answer. I accepted it, because it is obviously the answer to my question :) Sadly, it doesn't solve my problem completely. Let's say I define a `protocol` `Observer` that implements `AnyObject`. Next I create a class `ConcreteObservable` that implements `Observable`. I define `typealias T = Observer`. I get the following error: `Type 'ConcreteObservable' does not conform to protocol 'Observable'` `Protocol requires nested type 'T'` and `Possibly intended match 'T' (aka 'Observer') does not conform to 'AnyObject'` Any ideas of how to fix that? – hendra Mar 22 '16 at 18:54
  • @hendra: You have to make your class generic: `class ConcreteObservable : Observable { ... }`. – Martin R Mar 22 '16 at 19:01
  • Hm this doesn't really make sense to me. If I define this class as generic like you sad, I would need to declare a concrete type of an `Observer` during initialization of `ConcreteObservable`. But any object that conforms to `Observer` should be able to observe my `ConcreteObservable`. Or did I get something wrong? – hendra Mar 22 '16 at 19:22
  • 1
    @hendra: The problem is that the `Observable` protocol does not *conform* to `AnyObject` even if it inherits from that protocol: see http://stackoverflow.com/questions/33112559/protocol-doesnt-conform-to-itself, perhaps that helps. – Martin R Mar 22 '16 at 19:37
  • Does `Observable` protocol really need to define, how should i store the `Observer`'s ? @MartinR – Ratul Sharker Apr 20 '19 at 17:15