Reputation: 1120
I know this question has been asked before here. But the answers there do not satisfy my doubt.
I was told that they prevent mix-up of class types, the code below shows that they're not mixed up at all.
So, it shouldn't matter right?
Classes:
package Practice
abstract class Animal {
def name: String
}
abstract class Pet extends Animal {}
class Cat extends Pet {
override def name: String = "Cat"
}
class Dog extends Pet {
override def name: String = "Dog"
}
Here is the real confusion:
//Class with Upper Bound
class PetContainer[P <: Pet](p: P) {
def pet: P = p
}
//Class with Subtyping(Or Upcasting, I think they're the same)
class SimplePetContainer(p: Pet){
def pet: Pet = p
}
Driver Code:
val CatContainer: PetContainer[Cat] = new PetContainer[Cat](new Cat)
val DogContainer: SimplePetContainer = new SimplePetContainer(new Dog
println(CatContainer.pet.getClass)
println(DogContainer.pet.getClass)
Output:
class Practice.Cat
class Practice.Dog
//Practice was the package
Like I mentioned before, the classes are preserved.
So my question is, What advantage does Upper Bound have on Subtyping?
Upvotes: 1
Views: 72
Reputation: 262504
With your CatContainer
, you know that CatContainer.pet
is a Cat
at compile-time. Meaning that the compiler also knows that. So you can say
CatContainer.pet.meow()
For the SimplePetContainer
you do not have static type information about the pet
inside anymore.
Like I mentioned before, the classes are preserved.
At runtime, the pet
of course still knows its type (well, almost, it knows its class, which in your case would have been enough, any extra type information such as the generic types of that class has been erased).
But the variable DogContainer.pet
lacks information about what sort of Pet
it contains.
I was told that they prevent mix-up of class types
The compiler won't stop you from writing
val DogContainer = new SimplePetContainer(new Cat())
but it will reject this
val DogContainer = new PetContainer[Dog](new Cat())
Upvotes: 3