Why does the ListNode (Scala website) example handle different types?

An example ListNode taken from the Scalas homepage looks 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) } 

Using this class, we can create objects such as:

 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 add an integer value to the String node. I think this works because a parameter of type U will be automatically set to Any if an integer with prepend method is given (because Int not a supertype of String ).

When I try this using my own example with a lower bound, I 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 type param eter bounds [T >: String] val res2 = ^ <console>:12: error: type arguments [Int] do not conform to class E type param eter bounds [T >: String] new E[Int] ^ 

Why is the Int type not automatically considered here as the Any type, as in the ListNode example?


UPDATE 1 . This also works (without explicitly indicating that 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)))) 
+4
source share
2 answers

You get the above error because Int not a supertype of String .

Note that in the above code, ListNode String is a supertype of Null (see class hierarchy ) and Any is a supertype of String (as you correctly pointed out).

I would suggest that the confusion is caused by comparing two operations that actually do not match: new E[Int] creates an instance of the class with a parameter of type Int , which does not match the lower bound of String and therefore fails.

In the ListNode code above, on the other hand, you call the prepend method, which accepts a supertype of U T When creating anyList U (you guessed it) Any allowed, since this is the only common type of String and Int , so you can think of it as not passing the Int to it, but only to an arbitrary instance of Any (which also has type Int ).

Consequently,

 val anyList: ListNode[Int] = strList.prepend(12345) 

also does not work, since strList.prepend(12345) can only return ListNode[Any] .

+7
source

You do one fundamentally different: pass the type Int . Let us make the source code break, for example:

 scala> val anyList: ListNode[Any] = strList.prepend[Int](12345) <console>:11: error: type arguments [Int] do not conform to method prepend type parameter bounds [U >: String] val anyList: ListNode[Any] = strList.prepend[Int](12345) ^ 

Cm? If you specify Int , it will break. It worked in the original because 12345 was deduced as type Any , and not as type Int .

+1
source

All Articles