This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Why does asInstanceOf an extra internal coercion?

No replies
DaveScala
Joined: 2011-03-18,
User offline. Last seen 1 year 21 weeks ago.

I am playing with the code below and try to get parametric
polymorphism working. With the manifest I got rid of the unchecked
warnings due to type erasure, but now I still have one strange thing
in asInstanceOf. It seems that it does an extra coercion from
extension2.Neg to impl.Lit before it does the intended coercion to
extension.EvalExp. (btw I know that Scala has another way to solve the
expression problem, but that is not the issue here. I am not trying to
solve the expression problem)

This is the line:

final def asE[F: Manifest](e: F) = { val x =
manifest[E].erasure.cast(e); println(x.getClass); x.asInstanceOf[E] }

Is this a bug? Has it something to do with multiple inheritance by
mixins like upcasting along one road and downcasting along another?
Why doesn't keep asInstanceOf its input the same?

Output:
=====
C:\scala-2.9.1.final\examples
\hybridsolutionexpressionproblemmanifest>scala main
.Main
class extension2.Neg
java.lang.ClassCastException: Cannot cast impl.Lit to
extension.EvalExp
at java.lang.Class.cast(Class.java:3005)
at exprframework.Op.asE(expressionproblem.scala:28)
at exprframework.Op.apply(expressionproblem.scala:24)
at extension.Eval.eval(expressionproblem.scala:75)
at extension2.Neg.eval(expressionproblem.scala:95)
at extension.Eval.call(expressionproblem.scala:76)
at extension.Eval.call(expressionproblem.scala:73)
at exprframework.Op.apply(expressionproblem.scala:24)
at extension.Eval.eval(expressionproblem.scala:75)
at main.Main$delayedInit$body.apply(expressionproblem.scala:
109)
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(Traversab
leForwarder.scala:30)
at scala.App$class.main(App.scala:60)
at main.Main$.main(expressionproblem.scala:105)
at main.Main.main(expressionproblem.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run
$1.apply(ScalaClass
Loader.scala:78)
at scala.tools.nsc.util.ScalaClassLoader
$class.asContext(ScalaClassLoade
r.scala:24)
at scala.tools.nsc.util.ScalaClassLoader
$URLClassLoader.asContext(ScalaC
lassLoader.scala:88)
at scala.tools.nsc.util.ScalaClassLoader
$class.run(ScalaClassLoader.scal
a:78)
at scala.tools.nsc.util.ScalaClassLoader
$URLClassLoader.run(ScalaClassLo
ader.scala:101)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:33)
at scala.tools.nsc.ObjectRunner
$.runAndCatch(ObjectRunner.scala:40)
at scala.tools.nsc.MainGenericRunner.runTarget
$1(MainGenericRunner.scala
:56)
at
scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:80)

at scala.tools.nsc.MainGenericRunner
$.main(MainGenericRunner.scala:89)
at
scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

expressionproblem.scala
==================

package exprframework {

trait Exp {
def handle(v: Visitor)
}

trait Visitor {
def apply(e: Exp)
def default(e: Exp)
}

abstract class Node[V <: Visitor: Manifest] extends Exp {
final def handle(v: Visitor) {
if (isV(v)) accept(asV(v))
else v.default(this)
}
final def isV[W: Manifest](v: W) = { manifest[V] <:<
manifest[W] }
final def asV[W: Manifest](v: W) = { val x =
manifest[V].erasure.cast(v); println(x.getClass); x.asInstanceOf[V] }
private[exprframework] def accept(v: V)
}

abstract class Op[E <: Exp: Manifest] extends Visitor {
final def apply(e: Exp) {
if (isE(e)) call(asE(e))
else e.handle(this)
}
final def isE[F: Manifest](e: F) = { manifest[E] <:<
manifest[F] }
final def asE[F: Manifest](e: F) = { val x =
manifest[E].erasure.cast(e); println(x.getClass); x.asInstanceOf[E] }
private[exprframework] def call(e: E)
def default(e: Exp) {
throw new IllegalArgumentException("Expression problem
occurred!")
}
}
}
//implementation
package impl{
import exprframework._
trait AleVisitor extends Visitor {
def visitLit(lit: Lit)
def visitAdd(add: Add)
}

trait PrintExp extends Exp {
def print(print: Print)
}

class Print extends Op[PrintExp] with Visitor {
def call(e: PrintExp) { e.print(this) }
}

class Lit(val value: Int) extends Node[AleVisitor] with PrintExp {
def print(print: Print) { Console.print(value) }
def accept(v: AleVisitor) { v.visitLit(this) }
}

class Add(val left: Exp, val right: Exp) extends Node[AleVisitor]
with PrintExp {
def print(print: Print) {
print.apply(left); Console.print("+"); print.apply(right)
}
def accept(v: AleVisitor) { v.visitAdd(this) }
}
}
//extension
package extension {
import exprframework._
import impl._

trait EvalExp extends PrintExp {
def eval(eval: Eval): Int
}

class Eval extends Op[EvalExp] with AleVisitor {
private [this] var result = 0
final def eval(e: Exp) = { apply(e); result }
def call(e: EvalExp) { result = e.eval(this) }
def visitLit(lit: Lit) { result = lit.value }
def visitAdd(add: Add) { result = eval(add.left) +
eval(add.right) }
}
}
//further extension
package extension2 {
import exprframework._
import impl._
import extension._

trait NaleVisitor extends AleVisitor {
def visitNeg(neg: Neg)
}

class Neg(val exp: Exp) extends Node[NaleVisitor] with EvalExp {
def print(print: Print) {
Console.print("-("); print.apply(exp); Console.print(")")
}
def eval(eval: Eval) = { -eval.eval(exp) }
def accept(v: NaleVisitor) { v.visitNeg(this) }

}
}
package main {
import exprframework._
import impl._
import extension._
import extension2._
object Main extends App {
val lit = new Lit(5)
val neg = new Neg(lit)
val eval = new Eval
println(eval.eval(neg))
}
}

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland