Matching requirement type is not a generic parameter or related type
In Swift 2 I have the following protocols
protocol Fightable {
// return true if still alive, false if died during fight
func fight (other: Fightable) -> Bool
}
protocol Stats {
var defense: Int { get }
var attack: Int { get }
}
I can implement a protocol extension for Fightable to provide a common implementation fight
for all value types that match Stats
if I change the type signature fight
to
func fight (other: Self) -> Bool
and implement the extension as
extension Fightable where Self : Stats {
func fight (other: Self) -> Bool {
return self.defense > other.attack
}
}
The problem with the above implementation is that it requires the value types to be the same ( Human
can't fight Goblin
s). My current goal is to implement a protocol extension that provides a standard implementation fight
for any combination of value types as long as they implement Stats.
The following code
extension Fightable where Fightable : Stats {
func fight (other: Fightable) -> Bool {
return self.defense > other.attack
}
}
Produces an error
The type "Combat" in the compliance requirement is not a generic or related type
How can I make sure the other Fightable type also matches the Stats for this extension?
I am using XCode 7 beta 1.
source to share
One way that works for me is to do titalias in your battle log. Thus, you can limit the parameter of the combat function in your protocol extension. Because of this situation, you also need to make your combat function generic (Fightable can only be used as a general limitation).
In code, it looks like this:
protocol Fightable {
// make typealias
typealias F = Fightable
// make function generic
func fight<F: Fightable>(other: F) -> Bool
}
protocol Stats {
var defense: Int { get }
var attack: Int { get }
}
// constraint F and Self
extension Fightable where F : Stats, Self: Stats {
func fight(other: F) -> Bool {
return self.defense > other.attack
}
}
// example of an implementation
struct Human: Fightable {
func fight<F: Fightable>(other: F) -> Bool {
return true
}
}
source to share
Sorry, but I misunderstood your problem. So if I understand you correctly (hopefully), it is not possible to get a standard implementation of a function by fight
extending the protocol (at least with these restrictions). Because if you want to other
match Fightable
and Stats
, it is no longer the previous function where it other
could be anything Fightable
. Therefore, it does not fulfill the required function. As a workaround, I would suggest (taking your existing code):
protocol Fightable {
// return true if still alive, false if died during fight
func fight (other: Fightable) -> Bool
}
protocol Stats {
var defense: Int { get }
var attack: Int { get }
}
extension Fightable where Self : Stats {
// directly conforming to the protocol
func fight (other: Fightable) -> Bool {
if let otherStat = other as? Stats {
return self.defense > otherStat.attack
}
// providing a good way if other does not conform to Stats
return false
}
}
source to share