Closed scabug closed 12 years ago
Imported From: https://issues.scala-lang.org/browse/SI-5042?orig=1 Reporter: DaveScala (davescala) Affected Versions: 2.9.1 Attachments:
@paulp said: No unchecked warnings, prints -5. You appear to have multiple misapprehensions about how things work at runtime. You're never calling getClass on an instance whose type neither the compiler nor you know; from such beginnings one cannot be too surprised at CCEs.
diff --git a/expressionproblem.scala b/expressionproblem.scala
index fe31f7037d..55d30688dc 100644
--- a/expressionproblem.scala
+++ b/expressionproblem.scala
@@ -11,8 +11,10 @@ package exprframework {
abstract class Node[V <: Visitor: Manifest] extends Exp {
final def handle(v: Visitor) {
- if (manifest[V].erasure.cast(v).isInstanceOf[V]) accept(manifest[V].erasure.cast(v).asInstanceOf[V])
- else v.default(this)
+ if (manifest[V].erasure isAssignableFrom v.getClass)
+ accept(v.asInstanceOf[V])
+ else
+ v.default(this)
}
//final def isV[W <: Visitor: Manifest](v: W) = { manifest[V] <:< manifest[W] }
//final def asV(v: Visitor) = { val x = manifest[V].erasure.cast(v); println(x.getClass); x.asInstanceOf[V] }
@@ -21,8 +23,10 @@ package exprframework {
abstract class Op[E <: Exp: Manifest] extends Visitor {
final def apply(e: Exp) {
- if (manifest[E].erasure.cast(e).isInstanceOf[E]) call(manifest[E].erasure.cast(e).asInstanceOf[E])
- else e.handle(this)
+ if (manifest[E].erasure isAssignableFrom e.getClass)
+ call(e.asInstanceOf[E])
+ else
+ e.handle(this)
}
//final def isE[F <: Exp: Manifest](e: F) = { manifest[E] <:< manifest[F] }
//final def asE(e: Exp) = { val x = manifest[E].erasure.cast(e); println(x.getClass); x.asInstanceOf[E] }
DaveScala (davescala) said: Thanks, that works and I even found a shorter one:
manifest[V].erasure isAssignableFrom v.getClass
can be written as
manifest[V].erasure.isInstance(v)
At the moment isInstanceOf/asInstanceOf don't support (upper bounded) type parameters so it parametric polymorphism is not possible even if the type parameter has a manifest. All the manifest does is turning unchecked warnings off, there is still a class cast exception which is why a manifest solution makes the problem even worse.
In C# you can do just this and it works:
but in Scala you cannot do this even with a typeparameter with manifest: if (e.isInstanceOf[E]) call(e.asInstanceOf[E])
Work around 1
is only turning of the unchecked warnings in hackish way
Work around 2
brings the unchecked warning it back so it is circular
Both workarounds generate a class cast exception so a manifest doesn't help much: java.lang.ClassCastException: Cannot cast impl.Lit to extension.EvalExp
See enclosed: expressionproblem.cs expressionproblem.scala