3

i have following class hierarchy.

trait Item {val id: String}

case class MItem(override val id: String, val name: String) extends Item

class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name)

val d = new DItem("1", "one", "another one")
println(d)

Expected Output

DItem(1, one, another one)

Actual Output

Mitem(1,one)

Why is this happening. What is recommended so that i get the real type of my object and the not type of super class.

vsminkov
  • 10,912
  • 2
  • 38
  • 50
konquestor
  • 1,308
  • 3
  • 15
  • 29

3 Answers3

5

This is not a type erasure. You are getting this result because DItem gets toString() implementation inherited from Mitem. You have to override it to get what you want

class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) {
    override def toString = s"DItem($id, $name, $name2)"
}

So here is a result:

scala> val d = new DItem("1", "one", "another one")
d: DItem = DItem(1, one, another one)

scala> println(d)
DItem(1, one, another one)

It is almost always a bad idea to inherit from case classes because besides toString successor class will also inherit equals and hashCode.

Another drawback is limited pattern-matching for such successor classes i.e it is impossible to use such classes in case branches and may lead to confusing errors.

Example

case class A(id: String)
class B(id: String, name: String) extends A(id)

new B("foo", "bar") match {
  case A(id) => println(id)
  case other => println(other)
}

You may expect that there is no error in this code, but you'll get

<console>:17: error: constructor cannot be instantiated to expected type;
 found   : A
 required: B
     case A(id) => println(id)
          ^

However if you'll infer a type for B instance explicitly it will work

scala> new B("foo", "bar").asInstanceOf[A] match {
     |   case A(id) => println(id)
     |   case other => println(other)
     | }
foo

So... Inheriting from case classes is very error-prone and confusing and should be avoided unless you know what are you doing.

Community
  • 1
  • 1
vsminkov
  • 10,912
  • 2
  • 38
  • 50
2

Inheriting from case classes is deprecated as far as I know. So case classes can (should) only inherit from regular classes.

sandeep rawat
  • 4,797
  • 1
  • 18
  • 36
1

doing println usually invoke toString on the object pass on it.

so what happen on your code is, it will invoke the toString implementation of the object, it happens to be MItem that has this implementation.

so you need to override the toString on DItem like this:

class DItem(override val id: String, override val name: String, val name2: String) extends MItem(id, name) {
    override def toString = s"DItem($id, $name, $name2)"
}

if you want to just get the type of the object you can use getClass.

println(d.getClass)