I've wondered about this - a language that never lets you cast down, but you're allowed to cast up.
You can cast Cat to Animal, but never Animal to Cat.
I like how Go does it with a type switch.
Code:
switch animal := animal.(type) {
default:
// unknown animal
case *Cat:
// animal is now Cat
case *Dog:
// animal is now Dog
}
You could also imitate a type switch with an interface in pretty much any OO language without needing resorting to downcasting. Let's say you had an interface of all handlers for each animal type: (psuedo code)
Code:
interface AnimalTypes {
void IsCat(Cat *c);
void IsDog(Dog *d);
}
Then define your animals like this:
Code:
class Animal {
void GetAnimalType(AnimalTypes *handler);
}
class Cat : Animal {
void GetAnimalType(AnimalTypes *handler) {
handler->IsCat(this);
}
}
class Dog : Animal {
void GetAnimalType(AnimalTypes *handler) {
handler->IsDog(this);
}
}
Then if you want to cast your animal or get it's type, you could do:
Code:
void MakeSound(Animal *animal) {
animal->GetAnimalType(new AnimalTypes {
void IsCat(Cat *c) {
printf("Meow!");
}
void IsDog(Dog *d) {
printf("Woof!");
}
});
}