Below is the proto code,
message Animal {
optional string name = 1;
optional int32 age = 2;
}
message Dog{
optional string breed = 1;
}
Then the sample class using the above proto
public class InheritanceTest {
public static void main(String[] args){
Dog dog = Dog.getDefaultInstance();
printAnimalName(dog.getAnimal());
}
public static void printAnimal(Animal animal){
Dog dog = (Dog)animal; // Not at all possible right!
}
}
Is up-casting possible only by having an instance of dog as "required" in animal? or Is there any other way of upcasting?
First, to be clear: "Upcasting" means casting a Dog
to an Animal
. "Downcasting" means casting an Animal
to a Dog
. Your question is about how to upcast, but your example appears to be about downcasting. I'll try to answer both.
In my answer to your other question, I presented three options for emulating inheritance with protobufs.
Option 1 makes upcasting easy but does not allow for downcasting.
Options 2 and 3 make downcasting possible, but do not support upcasting.
If you need to be able to both upcast and downcast, then you need to use option 2 or 3, but always pass around an Animal
as simply an Animal
. That is, if you have a function which only works on Dog
, but needs to access some of the members of Animal
as well, it must take Animal
as its argument. The function's documentation should state that even though the argument type is Animal
, the argument must have the dog
field (or extension) set, i.e. it must actually be a Dog
. You should throw an IllegalArgumentException
otherwise.
Editorial: I know this is not a very satisfying answer. Protocol Buffers does not implement true inheritance because we couldn't come up with any design that seemed reasonable. The requirements of backwards- and forwards-compatibility on the wire make this problem a lot more complicated than it may seem. In practice, though, we've found that inheritance is rarely actually what you want anyway, and one of the options I presented usually works fine. In my opinion, inheritance makes sense for interfaces (i.e. collections of methods with behavior), but not for messages (i.e. collections of fields containing simple data).