Ilya Leoshkevich
2011-05-23 09:58:18 UTC
Hi,
Consider the following code:
trait Number[E <: Number[E]] { def add(e: E): E }
case class TheNumber(x: Int) extends Number[TheNumber] {
def add(e: TheNumber) = TheNumber(x + e.x)
}
object Boo {
def addAny[E <: Number[E]](e1: Any, e2: Any): E = {
e1.asInstanceOf[E].add(e2.asInstanceOf[E])
}
}
object Moo extends App {
val x1: Number[_] = TheNumber(1)
val x2: Number[_] = TheNumber(2)
val xs: List[Number[_]] = List(x1, x2)
val sum: Number[_] = xs.reduce((a, b) => Boo.addAny(a, b))
println(sum)
}
Here I define a function Boo.addAny(),
which assumes that its arguments are two Numbers of the same type and
adds them together.
The code compiles, but I get this at runtime:
***@q:~/nothing$ scalac Moo.scala && java -cp /opt/scala/lib/scala-
library.jar:. Moo
Exception in thread "main" java.lang.ClassCastException: TheNumber
cannot be cast to scala.runtime.Nothing$
at Moo$$anonfun$1.apply(Moo.scala:17)
at Moo$$anonfun$1.apply(Moo.scala:17)
at scala.collection.LinearSeqOptimized
$class.foldLeft(LinearSeqOptimized.scala:111)
at scala.collection.immutable.List.foldLeft(List.scala:45)
at scala.collection.LinearSeqOptimized
$class.reduceLeft(LinearSeqOptimized.scala:125)
at scala.collection.immutable.List.reduceLeft(List.scala:45)
at scala.collection.TraversableOnce
$class.reduce(TraversableOnce.scala:180)
at scala.collection.immutable.List.reduce(List.scala:45)
at Moo$delayedInit$body.apply(Moo.scala:17)
at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV
$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:60)
at scala.App$$anonfun$main$1.apply(App.scala:60)
at scala.collection.LinearSeqOptimized
$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:45)
at scala.collection.generic.TraversableForwarder
$class.foreach(TraversableForwarder.scala:30)
at scala.App$class.main(App.scala:60)
at Moo$.main(Moo.scala:13)
at Moo.main(Moo.scala)
Note that reduce() is of importance here.
When the numbers are added directly like so:
val sum: Number[_] = Boo.addAny(x1, x2)
there is no runtime error:
***@q:~/nothing$ scalac Moo.scala && java -cp /opt/scala/lib/scala-
library.jar:. Moo
TheNumber(3)
Why is it trying to cast TheNumber to Nothing?
I would assume it inferred E=Nothing, but then, why this didn't happen
in the second case?
Best regards,
Ilya
Consider the following code:
trait Number[E <: Number[E]] { def add(e: E): E }
case class TheNumber(x: Int) extends Number[TheNumber] {
def add(e: TheNumber) = TheNumber(x + e.x)
}
object Boo {
def addAny[E <: Number[E]](e1: Any, e2: Any): E = {
e1.asInstanceOf[E].add(e2.asInstanceOf[E])
}
}
object Moo extends App {
val x1: Number[_] = TheNumber(1)
val x2: Number[_] = TheNumber(2)
val xs: List[Number[_]] = List(x1, x2)
val sum: Number[_] = xs.reduce((a, b) => Boo.addAny(a, b))
println(sum)
}
Here I define a function Boo.addAny(),
which assumes that its arguments are two Numbers of the same type and
adds them together.
The code compiles, but I get this at runtime:
***@q:~/nothing$ scalac Moo.scala && java -cp /opt/scala/lib/scala-
library.jar:. Moo
Exception in thread "main" java.lang.ClassCastException: TheNumber
cannot be cast to scala.runtime.Nothing$
at Moo$$anonfun$1.apply(Moo.scala:17)
at Moo$$anonfun$1.apply(Moo.scala:17)
at scala.collection.LinearSeqOptimized
$class.foldLeft(LinearSeqOptimized.scala:111)
at scala.collection.immutable.List.foldLeft(List.scala:45)
at scala.collection.LinearSeqOptimized
$class.reduceLeft(LinearSeqOptimized.scala:125)
at scala.collection.immutable.List.reduceLeft(List.scala:45)
at scala.collection.TraversableOnce
$class.reduce(TraversableOnce.scala:180)
at scala.collection.immutable.List.reduce(List.scala:45)
at Moo$delayedInit$body.apply(Moo.scala:17)
at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV
$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:60)
at scala.App$$anonfun$main$1.apply(App.scala:60)
at scala.collection.LinearSeqOptimized
$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:45)
at scala.collection.generic.TraversableForwarder
$class.foreach(TraversableForwarder.scala:30)
at scala.App$class.main(App.scala:60)
at Moo$.main(Moo.scala:13)
at Moo.main(Moo.scala)
Note that reduce() is of importance here.
When the numbers are added directly like so:
val sum: Number[_] = Boo.addAny(x1, x2)
there is no runtime error:
***@q:~/nothing$ scalac Moo.scala && java -cp /opt/scala/lib/scala-
library.jar:. Moo
TheNumber(3)
Why is it trying to cast TheNumber to Nothing?
I would assume it inferred E=Nothing, but then, why this didn't happen
in the second case?
Best regards,
Ilya