The ListNode example, taken from Scalas homepage goes like this:
case class ListNode[+T](h: T, t: ListNode[T]) {
def head: T = h
def tail: ListNode[T] = t
def prepend[U >: T](elem: U): ListNode[U] =
ListNode(elem, this)
}
With this class, we can create objects like:
val empty: ListNode[Null] = ListNode(null, null)
val strList: ListNode[String] = empty.prepend("hello")
.prepend("world")
val anyList: ListNode[Any] = strList.prepend(12345)
As we can see, we can prepend an integer value to a String
node. I guess, this works because the type parameter U
will be automatically set to Any
, when given the integer to the prepend
method (because Int
is not a supertype of String
).
When trying this with an own lower bound example, I will get an error:
scala> class E[T >: String]
defined class E
scala> new E[Any]
res1: E[Any] = E@135f0a
scala> new E[Int]
<console>:11: error: type arguments [Int] do not conform to class E's type param
eter bounds [T >: String]
val res2 =
^
<console>:12: error: type arguments [Int] do not conform to class E's type param
eter bounds [T >: String]
new E[Int]
^
Why is the type Int
here not automatically seen as type Any
like in the ListNode
example ?
UPDATE 1: This also works (without explicitley saying the new ListNode
should be of type Any
)
scala> val empty: ListNode[Null] = ListNode(null, null)
empty: example.listNode.ListNode[Null] = ListNode(null,null)
scala> empty.prepend("hello").prepend("world")
res0: example.listNode.ListNode[java.lang.String] = ListNode(world,ListNode(hell
o,ListNode(null,null)))
scala> val strList: ListNode[String] = empty.prepend("hello").prepend("world")
strList: example.listNode.ListNode[String] = ListNode(world,ListNode(hello,ListN
ode(null,null)))
scala> strList.prepend(12345)
res1: example.listNode.ListNode[Any] = ListNode(12345,ListNode(world,ListNode(he
llo,ListNode(null,null))))
You get the above error because Int
is not a supertype of String
.
Note that in the ListNode
code above, String
is a supertype of Null
(see class hierarchy), and Any
is a supertype of String
(as you rightly pointed out).
I would guess the confusions is caused by comparing two operations that are not really the same: new E[Int]
instantiates the class with the type parameter Int
, which is not conformant to the lower bound String
and hence fails.
In the ListNode
code above, on the other hand, you call the prepend
method that takes a supertype U
of T
. When creating anyList
, U
is (just as you guessed) resolved to Any
since this is the only common supertype of String
and Int
, so you could think of it as not really passing an Int
to it, but just some arbitrary instance of Any
(which also happens to be of type Int
).
Therefore,
val anyList: ListNode[Int] = strList.prepend(12345)
fails as well, as strList.prepend(12345)
can only return ListNode[Any]
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With