I am trying to understand why the where clause of a generic method is ignored
I made a simple usage example in Swift 3 (you can copy the code on the playground if you want to play with it):
//MARK: - Classes protocol HasChildren { var children:[Human] {get} } class Human {} class SeniorHuman : Human, HasChildren { var children: [Human] { return [AdultHuman(), AdultHuman()] } } class AdultHuman : Human, HasChildren { var children: [Human] { return [YoungHuman(), YoungHuman(), YoungHuman()] } } class YoungHuman : Human {} //MARK: - Generic Methods /// This method should only be called for YoungHuman func sayHelloToFamily<T: Human>(of human:T) { print("Hello \(human). You have no children. But do you conform to protocol? \(human is HasChildren)") } /// This method should be called for SeniorHuman and AdultHuman, but not for YoungHuman... func sayHelloToFamily<T: Human>(of human:T) where T: HasChildren { print("Hello \(human). You have \(human.children.count) children, good for you!") }
So now let's run some tests. If we have:
let senior = SeniorHuman() let adult = AdultHuman() print("Test #1") sayHelloToFamily(of: senior) print("Test #2") sayHelloToFamily(of: adult) if let seniorFirstChildren = senior.children.first { print("Test #3") sayHelloToFamily(of: seniorFirstChildren) print("Test #4") sayHelloToFamily(of: seniorFirstChildren as! AdultHuman) }
Output:
Test
Well ... apparently, in order to work on the where protocol proposal, we need to pass a strong type that matches the protocol in its definition.
Just using supertypes is not enough, even if in test No. 3 it is obvious that this instance really matches the HasChildren protocol.
So, what am I missing here, is it simply impossible? Do you have links containing additional information about what is happening, or more information about where clauses or subtypes and their behavior in general?
I read some useful resources, but none of them have an exhaustive explanation of why it does not work:
source share