In the following code:
def test(list: List[Any]): Unit = {
list.foreach {
v =>
v match {
case r: AnyRef => println(r + ": " + r.getClass.getName)
case d: Double => println(d + ": Double")
case f: Float=> println(f + ": Float")
case b: Byte => println(b + ": Byte")
case c: Char => println(c + ": Char")
case s: Short => println(s + ": Short")
case i: Int => println(i + ": Int")
case l: Long=> println(l + ": Long")
case b: Boolean => println(b + ": Boolean")
case _ => throw new IllegalArgumentException("Unknown type: " + v)
}
}
}
test(List(0L, 1.asInstanceOf[Int], 2.asInstanceOf[Short]))
here is the output (Scala 2.8.1):
0: java.lang.Long
1: java.lang.Long
2: java.lang.Long
Why are the numbers being promoted to java.lang.Long? How can I do this so that they either keep their AnyVal types or get "boxed" to the equivalent AnyRef type?
Following are the point of difference between lists and array in Scala: Lists are immutable whereas arrays are mutable in Scala. Lists represents a linked list whereas arrays are flat.
Specific to Scala, a list is a collection which contains immutable data, which means that once the list is created, then it can not be altered. In Scala, the list represents a linked list. In a Scala list, each element need not be of the same data type.
Lists are immutable --- the elements of a list cannot be changed, Lists are recursive (as you will see in the next subsection), Lists are homogeneous: A list is intended to be composed of elements that all have the same type.
This is the first method we use to append Scala List using the operator “:+”. The syntax we use in this method is; first to declare the list name and then use the ':+' method rather than the new element that will be appended in the list. The syntax looks like “List name:+ new elements”.
I think the answer is in Section 3.5.3 of the language reference:
Because of this, Scala infers that the common type between Short, Int and Long is Long and then converts the non-Long objects to Longs:
scala> List(0L, 0, 0: Short)
res1: List[Long] = List(0, 0, 0)
If you want to use the whole chain of weak conformance, try:
scala> List(0: Byte, 1: Short, 'c', 3, 4L, 5.0f, 6.0)
res2: List[Double] = List(0.0, 1.0, 99.0, 3.0, 4.0, 5.0, 6.0)
And, of course to say that you want a List[Any], just add [Any] to your call to List:
scala> List[Any](0: Byte, 1: Short, 'c', 3, 4L, 5.0f, 6.0)
res11: List[Any] = List(0, 1, c, 3, 4, 5.0, 6.0)
Type inference works by starting with the most restrictive type (e.g. Nothing) and widening until one type can contain everything. For numeric values, this means widening from Int to Long. But now, since the call is effectively to List[Long](ls: Long*) all the numeric values are promoted in advance.
So, for instance, all of these give the same list:
List(1, 2: Byte, 3: Long)
List(1L, 2, 3: Short)
List(1: Byte, 2: Long, 3: Byte)
namely a List[Long](1L, 2L, 3L). Now, if you don't like this behavior, specify the type of the list as AnyVal or Any:
List[Any](1, 2: Byte, 3: Long)
List.head.asInstanceOf[AnyRef].getClass // java.lang.Integer
Edit: P.S. if you are specifying a constant of a certain type, you should just state the type (e.g. (2: Short)) instead of casting it to that type (e.g. 2.asInstanceOf[Short]).
List[Any](0L, 1.asInstanceOf[Int], 2.asInstanceOf[Short])
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