Search code examples
iosgenericsswift-extensionsswift-protocols

Can't invoke protocol method on generic type restricted by other protocol


I have the following:

protocol Guard {

    var prisoners: Array<Prisoner>? { get set }

    func smack<T: Prisoner>(prisoner: T)

    func smackAll()


}

extension Guard {

    final func smackAll() {

        prisoners?.forEach() { smack($0) }

        //ERROR: "Cannot invoke 'smack' with an argument list of type '(Prisoner)'"

    }

}

protocol Prisoner {

    var guards: Array<Guard>? { get set }

}

extension Prisoner {

   final func incurBeating() {

        guards?.forEach() { $0.smack(self) }

    }

}

I wish to assign the Guard protocol to any number of objects of different class types, and Prisoner to other objects. The objects acting as guards will have their own smack implementations, according to their class type. But I see no reason to re-write smackAll in each class that might inherit Guard. So I'm trying to do it like this, but the compiler isn't letting me. What am I missing?


Solution

  • The following seems to work for me.

    protocol Guard {
        var prisoners: Array<Prisoner>? { get set }
        func smack<Prisoner>(prisoner: Prisoner)
        func smackAll()
    }
    
    extension Guard {
        func smackAll() {
            prisoners?.forEach() { smack($0) }
             //ERROR: "Cannot invoke 'smack' with an argument list of type '(Prisoner)'"
        }
    }
    
    protocol Prisoner {
         var guards: Array<Guard>? { get set }
    }
    

    Note: func smack(prisoner: Prisoner) you don't need to use T: Prisoner. It's already an interface and can be referred to the interface, it won't let you put anything in there that isn't a Prisoner implementer anyway. The only case you would use this is to add more constraint to a concrete class like T: Where MyConcrete implements Prisoner