Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Compiler not show error "protocol type 'P' cannot conform to 'P'"

protocol Animal {
    func makeNoise()
    static var species: String { get }
}
struct Dog: Animal {
    func makeNoise() { print("Woof") }
    static var species: String = "Canus familiaris"
}
struct Cat: Animal {
    func makeNoise() { print("Meow") }
    static var species: String = "Felis catus"
}

var animal: Animal // `Animal` is used here as a type.
animal = Dog()
animal.makeNoise() // Prints "Woof".
animal = Cat()
animal.makeNoise() // Prints "Meow".

func declareAnimalSpecies<T: Animal>(_ animal: T) {
    animal.makeNoise()
    print("My species is known as (T.species)")
}

let dog = Dog()
declareAnimalSpecies(dog)
// Prints:
// "Woof"
// "My species is known as Canus familiaris"
declareAnimalSpecies(animal) // <- not show error here
// error: protocol type 'Animal' cannot conform to 'Animal'...`

I’m taking example code from swift git. As I understand that animal ‘s type is any Animal so when it is passed to function declareAnimalSpecies , the compiler will infer that T is any Animal and because any Animal cannot conform to Animal so I’m expecting that it will show that error.

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

This is allowed since the implementation of SE-0352. This allows us to "open existential boxes" when calling generic methods. SE-0375 further allows us to do the same with optional parameters.

animal is an existential "box" that at runtime, holds an actual concrete type that conforms to Animal inside at. Instead of solely looking at the type constraints and saying "any Animal does not conform to Animal", the compiler is now able to see that this is a box, and in it there must be some concrete type. At runtime, it is guaranteed that there is a T that conforms to its type constraint.

As a counterexample, consider

func foo<T: Animal>(_ a: T, _ b: T) {}
func bar(_ a: any Animal, _ b: any Animal) {
    foo(a, b) // error
}

This is not allowed because the existential boxes a and b might contain different concrete types at runtime, so there is not necessarily a single T type that can passed to foo.


It is important to note that, from the POV of the type system, any Animal still does not conform to Animal. If you have

struct Foo<T: Animal> {}

you still cannot write Foo<any Animal>. There are no existential boxes to open in this case.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading