2
class Bar { override def toString() = "Bar" }
case class Foo(s: String) extends Bar
Foo("bar") // "Bar"

Why doesn't Foo get it's toString generated? Is it a bug or is there actually a reason? Is there any way to "get it back" (is there a default implementation somewhere that works for case classes perhaps)?

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
Dima
  • 39,570
  • 6
  • 44
  • 70

2 Answers2

5

It is not a bug, it is the specified behavior that the case class gets it's implementation from the parent instead of generating one of it's own.

It's mentioned in the Scala Specification §5.3.2:

Every case class implicitly overrides some method definitions of class scala.AnyRef unless a definition of the same method is already given in the case class itself or a concrete definition of the same method is given in some base class of the case class different from AnyRef. In particular:

  • Method toString: String returns a string representation which contains the name of the class and its elements.

I think the only way to make this work would be to explicitly override toString again in Foo yourself.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • Yeah, I get it, that I have to override `toString` ... The question is _what_ do I override it to? Is there a function somewhere I can call to get the default behavior, or do I have to actually repeat the whole implementation? – Dima Jul 13 '17 at 15:31
  • @Dima You mean: "Is there an API to provide a case class and get a string representation of that class"? If so, not sure, perhaps looking at the decompiled `toString` on an arbitrary case class, though I'd argue it's probably some compiler implementation detail. – Yuval Itzchakov Jul 13 '17 at 15:39
  • @Dima Maybe this can help: https://stackoverflow.com/questions/15718506/scala-how-to-print-case-classes-like-pretty-printed-tree – Yuval Itzchakov Jul 13 '17 at 15:41
2

To reproduce the default implementation, you can use

override def toString() = productPrefix + productIterator.mkString("(", ", ", ")")

I seem to remember this method being somewhere in the standard library, but couldn't find it just now. Of course this will be less efficient than implementing it manually e.g. as productPrefix + "(" + field1 + ", " + ..., but this method is not going to be a hotspot in most cases, and it gives less opportunity for error.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Does it work for nested structures? i.e case class inside a case class? – Yuval Itzchakov Jul 13 '17 at 16:55
  • 1
    It'll use the `toString` method of that case class, which will again be either default or implemented by you, and it shouldn't matter which (as far as I am aware). Of course, if you want pretty-printing as in https://stackoverflow.com/questions/15718506/scala-how-to-print-case-classes-like-pretty-printed-tree, things get more complicated, but the standard implementation doesn't do that. – Alexey Romanov Jul 13 '17 at 17:00
  • 1
    I think the method you were trying to remember is `ScalaRuntime._toString(this)` as mentioned [here](https://stackoverflow.com/a/27467406/349831) :) – Jack May 13 '19 at 07:56