Discussion:
java.lang.ClassCastException: TheNumber cannot be cast to scala.runtime.Nothing$
Ilya Leoshkevich
2011-05-23 09:58:18 UTC
Permalink
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
Luc Duponcheel
2011-05-23 10:34:00 UTC
Permalink
strange error indeed (at least: at first sight)

btw:

is there a particular reason why you do not define things like

class Boo[E] {
def addAny[E <: Number[E]](e1: E, e2: E): E = {
e1.add(e2)
}
}

object IntBoo extends Boo[Int]

(and use IntBoo in Moo)

or were you just experimenting with the type system?

Luc
Post by Ilya Leoshkevich
Hi,
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.
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.
val sum: Number[_] = Boo.addAny(x1, x2)
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
--
__~O
-\ <,
(*)/ (*)

reality goes far beyond imagination
Loading...