Scala Programming Language
  1. Scala Programming Language
  2. SI-5042

isInstanceOf/asInstanceOf support for parametric polymorphism (manifest doesn't help and turns of unchecked warning which makes it worse)

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Not a Bug
    • Affects Version/s: Scala 2.9.1
    • Fix Version/s: None
    • Component/s: Misc Library

      Description

      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:

      if (e is E) call((E)e);
      

      but in Scala you cannot do this even with a typeparameter with manifest:
      if (e.isInstanceOf[E]) call(e.asInstanceOf[E])

      Work around 1
      =============

      if(isE(e) call(asE(e))
      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] }
      

      is only turning of the unchecked warnings in hackish way

      Work around 2
      =============

      if (manifest[E].erasure.cast(e).isInstanceOf[E]) call(manifest[E].erasure.cast(e).asInstanceOf[E])
      

      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

      1. expressionproblem.cs
        2 kB
        DaveScala
      2. expressionproblem.scala
        3 kB
        DaveScala

        Activity

        Hide
        Paul Phillips added a comment -

        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] }
        
        Show
        Paul Phillips added a comment - 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] }
        Hide
        DaveScala added a comment -

        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)
        
        Show
        DaveScala added a comment - 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)

          People

          • Assignee:
            Paul Phillips
            Reporter:
            DaveScala
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development