To answer the question officially asked: Yes, Swift allows more "restricted" return types in return types. This property is formally called return type Covariance. Consider this example, which is compilable Swift code:
class Pet {}
class Dog: Pet {}
class House {
func getPets() -> Pet {
return Pet()
}
}
class DogHouse: House {
override func getPets() -> Dog {
return Dog()
}
}
However, the issue here is that Array<Dog>
is not a "more restricted" type than Array<Pet>
, and conversely, Array<Pet>
is not a generalization of Array<Dog>
. Formally, Array<Dog>
is not a covariant of Array<Pet>
.
To illustrate why that is, consider this example:
class House<T> {
var occupants = [T]()
func addOccupant(_ o: T) {
occupants.append(o)
}
}
class Pet {}
class Dog: Pet {}
class Cat: Pet {}
class PetHouseBuilder {
func buildHouse() -> House<Pet> {
return House()
}
}
class DogHouseBuilder: PetHouseBuilder {
// Suppose this were legal
override func buildHouse() -> House<Dog> {
return House()
}
}
// The concrete return type of the object is `House<Dog>`, but
// `PetHouseBuilder.buildHouse` has a static return type of `House<Pet>`,
// so `petHouse` will have an inferred static type of `House<Pet>`
let petHouse = PetHouseBuilder().buildHouse()
let vulnerableLittle = Cat()
petHouse.addOccupant(vulnerableLittle)
// Oh boy, now there's a kitten in the dog house ☠️