on code below.
My expectation is that T
must be a of type B
or A
, so call to lowerBound(new D)
should probably not compile (?). Similar experiments with upperbound give me expected typecheck errors.
Thanks for giving the hint.
object varianceCheck {
class A {
override def toString = this.getClass.getCanonicalName
}
class B extends A
class C extends B
class D extends C
def lowerBound[T >: B](param: T) = { param }
println(lowerBound(new D)) //> varianceCheck.D
}
With your implementation you can write:
scala> def lowerBound[T >: B](param: T) = { param }
lowerBound: [T >: B](param: T)T
scala> lowerBound(new AnyRef {})
res0: AnyRef = $anon$1@2eef224
where AnyRef
is a super type of all object/reference types (actually it is an alias for Java Object
class). And this is right, T >: B
expresses that the type parameter T
or the abstract type T
refer to a supertype of type B
.
You just have a bad example with toString
, cause this method has all object types, but if you change it to, let's say on someMethod
, your lowerBound
won't compile:
<console>:18: error: value someMethod is not a member of type parameter T
def lowerBound[T >: B](param: T) = { param.someMethod }
If you change this to T <: B
, which means that parameter of type T
is a subclass of B
, than everything is good, cause this param
has someMethod
method:
def lowerBound[T <: B](param: T) = { param.someMethod }
Faced same question as well. Seems compiler doing great job to help us shoot our feets. If you extract result of the lowerBound you may notice that it is of type B
val b: B = lowerBound(new D)
println(b) //> varianceCheck.D
And then if you try though to request type D explicitly
lowerBound[D](new D)
you will see the compiler error that you expected:
Error:(12, 21) type arguments [D] do not conform to method lowerBound's type parameter bounds [T >: B]
lowerBound[D](new D)