@joshlemer The idea is for the string representation to be exactly the code typed to create the instance, I would there fore expect expect the string to contain the escape. If I were to implement it, I would probably look at how it’s done in https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#escapeJava(java.lang.String) and start from there.
I recommend you check out pprint as it works pretty much as you’re describing http://www.lihaoyi.com/PPrint/
The PR https://github.com/scala/scala/pull/6951 adding productElementNames has been reviewed by Jason Zaugg from the compiler team with actionable feedback if someone wants to pick this up.
thanks for the pointer, since this thread was originally about changing the toString behaviour, I wish it would behave like pprint
but I will look into integrating pprint for my projects thought that won’t help with teaching scala classes.
You can get pretty close to case classes a la carte in current Scala: see my Scala eXchange talk from 2014 and an example in the shapeless tree. It would probably make sense to think about this as a target for generic programming in Scala 3.
The PR https://github.com/scala/scala/pull/6972 has been merged adding the method productElementName
to case classes. This means that it’s possible to implement the functionality propsed here without macros or runtime reflection
def pretty(p: Product): String =
p.productElementNames.zip(p.productIterator)
.map { case (name, value) => s"$name=$value" }
.mkString(p.productPrefix + "(", ", ", ")")
pretty(User("Susan", 42))
// User(name=Susan, age=42)
I started a discussion on adding such a pretty-printing function to the standard library https://github.com/scala/scala/pull/6972#issuecomment-411360323
and they lived happily ever after
The end
I found myself coming back to this thread a few times to copy-paste the pretty function by @olafurpg. For anyone else doing similar, here is that function wrapped up in a trait for easier consumption
trait PrettyProduct extends Product {
override def toString: String = {
this
.productElementNames
.zip(this.productIterator)
.map { case (name, value) => s"$name=$value" }
.mkString(this.productPrefix + "(", ", ", ")")
}
}
final case class Apple(a: Int, b: String) extends PrettyProduct
println(Apple(a=3, b="hello")); // Apple(a=3, b=hello)
Just stumbled on a draft PR by som-snytt that implements pretty printing of case classes with field names https://github.com/scala/scala/pull/8885
scala> val a = Sum("A", "B")
val a: Sum = Sum(exp = "A", exp2 = "B")
Personally I think this feature would greatly help with debugging and reading logs.
For me, in some cases it’s worthy, in others it’s too wordy
I would liked it better if the REPL just provided a Show
type class that we can configure.
Ammonites allows you to configure the pretty-printer, and with a bit of work could show field names too [WIP] Include field names in rendering of Product (Scala 2.13 only) by cb372 · Pull Request #38 · com-lihaoyi/PPrint · GitHub
Is it thinkable, to change the behavior of generated toString
to include both field names and properly quoted strings, at least in Scala 3, if it is too big of a change for Scala 2.x?
https://github.com/lihaoyi/PPrint gives you properly quoted strings, colors, nice indentation, streaming/incremental printing (e.g. for the first N lines of huge data structures) and a bunch of other things. If you’re still using println
debugging, it’s definitely worth giving pprint.log
a try
Ideally with a way to easily create either a concise or verbose default implementation, as appropriate for the data structure.
PPrint 0.6.0 implemented support in Include field names in rendering of Product (Scala 2.13 only) #38, for example
case class Address(planet: String, city: String)
case class User(name: String, age: Int, address: Address)
pprint.pprintln(User("Picard", 75, Address("Earth", "San Francisco")), width = 80, height = 80)
outputs
User(
name = "Picard",
age = 75,
address = Address(planet = "Earth", city = "San Francisco")
)
Yep! I was about the post here, but you beat me to it.
There’s a field you can override on PPrinter to revert to the old behavior, but the new behavior is useful enough i turned it on by default for Scala 2.13
Any chance that’ll get backported to 2.12?
From the PR:
“This is only available in Scala 2.13 because it makes use of productElementNames. The behaviour is unchanged in Scala 2.11/2.12.”
I’m aware, just wondering if that might change as this feature gets more traction
You mean adding the productElementNames method to case classes in 2.12?