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
Intis not a supertype ofString.Note that in the
ListNodecode above,Stringis a supertype ofNull(see class hierarchy), andAnyis a supertype ofString(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 parameterInt, which is not conformant to the lower boundStringand hence fails.In the
ListNodecode above, on the other hand, you call theprependmethod that takes a supertypeUofT. When creatinganyList,Uis (just as you guessed) resolved toAnysince this is the only common supertype ofStringandInt, so you could think of it as not really passing anIntto it, but just some arbitrary instance ofAny(which also happens to be of typeInt).Therefore,
fails as well, as
strList.prepend(12345)can only returnListNode[Any].