Today I spent a few hours to understand the logic behind Lower Bounds in Scala but the more I read the more confusing it gets. Would you please shed some light on this?
Here is the simple class hierarchy for our workshop:
class Animal
class Pet extends Animal
class Wild extends Animal
class Dog extends Pet
class Cat extends Pet
class Lion extends Wild
class Tiger extends Wild
So the hierarchy would be something like:
Animal
/ \
Pet Wild
/ \ / \
Dog Cat Lion Tiger
And here is the client code:
object Main extends App {
//I expect the compilation of passing any type above Pet to fail
def upperBound[T <: Pet](t: T) = {println(t.getClass.getName)}
//I expect the compilation of passing any type below Pet to fail
def lowerBound[T >: Pet](t: T) = {println(t.getClass.getName)}
upperBound(new Dog)//Ok, As expected
upperBound(new Cat)//Ok, As expected
upperBound(new Pet)//Ok, As expected
//Won't compile (as expected) because Animal is not a sub-type of Pet
upperBound(new Animal)
lowerBound(new Pet)//Ok, As expected
lowerBound(new Animal)//Ok, As expected
//I expected this to fail because Dog is not a super type of Pet
lowerBound(new Dog)
//I expected this to fail because Lion is not a super type of Pet either
lowerBound(new Lion)
lowerBound(100)//Jesus! What's happening here?!
lowerBound(Nil)// Ok! I am out!!! :O
}
Well... The last four lines of the code does not make any sense to me! From what I understand, Lower Bound does not impose any constraints on the type parameter at all. Is there an implicit Bound to Any
or AnyRef
somewhere which I am missing?