0
    import scala.annotation.unchecked.uncheckedVariance
    import scala.collection.immutable.Queue
    import scala.collection.mutable.ListBuffer


  abstract class Exp[+T:Manifest] { // constants/symbols (atomic)
    def tp: Manifest[T @uncheckedVariance] = manifest[T] //invariant position! but hey...
  }
  case class Sym[+T:Manifest](val id: Int) extends Exp[T] {
  }
  abstract class Def[+T] { // operations (composite)
    override final lazy val hashCode = scala.runtime.ScalaRunTime._hashCode(this.asInstanceOf[Product])
  }
  abstract class Stm
  case class TP[+T](sym: Sym[T], rhs: Def[T]) extends Stm

  abstract class Trial{
  }

  class M1() extends Trial{}
  class M2() extends Trial{}

  class N1() extends Def[M1]{}
  class N2() extends Def[M2]{}

  TP(Sym[M1]{4},new N1())

This gives the following error:

scala> TP(Sym[M1]{4},new N1()) java.lang.ClassCastException: class N1 cannot be cast to class scala.Product (N1 is in unnamed module of loader scala.tools.nsc.interpreter.IMain$TranslatingClassLoader @2098d37d; scala.Product is in unnamed module of loader 'bootstrap')
at Def.hashCode$lzycompute(:13) at Def.hashCode(:13) at java.base/java.lang.Object.toString(Object.java:246) at java.base/java.lang.String.valueOf(String.java:2951) at java.base/java.lang.StringBuilder.append(StringBuilder.java:168) at scala.collection.IterableOnceOps.addString(IterableOnce.scala:1194)
at scala.collection.IterableOnceOps.addString$(IterableOnce.scala:1186)
at scala.collection.AbstractIterator.addString(Iterator.scala:1279)
at scala.collection.IterableOnceOps.mkString(IterableOnce.scala:1136) at scala.collection.IterableOnceOps.mkString$(IterableOnce.scala:1134) at scala.collection.AbstractIterator.mkString(Iterator.scala:1279)
at scala.runtime.ScalaRunTime$._toString(ScalaRunTime.scala:159) at TP.toString(:18) at scala.runtime.ScalaRunTime$.inner$1(ScalaRunTime.scala:261) at scala.runtime.ScalaRunTime$.stringOf(ScalaRunTime.scala:266) at scala.runtime.ScalaRunTime$.replStringOf(ScalaRunTime.scala:274) at .lzycompute(:8) ... 28 elided

I was expecting an object of type TP[Trial], what happened? Since Sym and Def are covariant types. Am I missing something?

Thanks

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
PheniX Tylor
  • 41
  • 1
  • 4
  • 4
    What does all of this have to do with the fact that `N1` and `N2` cannot be cast into `Product` by `this.asInstanceOf[Product]`? Make `N1` and `N2` into `case class`-es, then it runs without exceptions. It all looks quite complicated, more complicated than the names of the involved entities suggest. Would you mind briefly describing what you are trying to accomplish? – Andrey Tyukin Sep 30 '20 at 19:16
  • @AndreyTyukin, I really don't understand why N1 and N2 has to be case classes, Can you explain? – PheniX Tylor Sep 30 '20 at 19:25
  • 2
    The documentation on [Product](https://www.scala-lang.org/api/2.12.4/scala/Product.html) basically lists all the common implementations of that trait - those are, essentially, tuples and case classes. Since `N1` is clearly not a tuple, it probably should be a `case class` if it's supposed to not cause any `ClassCastException`s. What did you expect from that `Product` type cast? – Andrey Tyukin Sep 30 '20 at 19:29

1 Answers1

1

At Scastie it isn't reprodusible as https://scastie.scala-lang.org/tCD4HahgTqO4WTnlGcfWqQ but is reprodusible as https://scastie.scala-lang.org/L46PWLF2S5i4d1IGoT6UuQ

Locally I can reproduce ClassCastException only if I remove lazy for Def#hashCode.

Covariance is irrelevant.

In this.asInstanceOf[Product] you're trying to cast Def's this to Product. When you create new N1() it is current Def's this.

new N1() as a value of class N1 cannot be cast to Product because N1 doesn't extend Product.

In Scala by default classes do not extend Product, case classes do.

To fix ClassCastException it's enough to make N1 a case class.

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66