New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide better toString for case classes #3967
Comments
Imported From: https://issues.scala-lang.org/browse/SI-3967?orig=1 |
Ittay Dror (ittayd) said: |
@paulp said: Also, we're still missing the reflection lib you need to write your desired toString method in a non-hack way (to get the parameter names.) |
Ittay Dror (ittayd) said: If I understand correctly, today toString is implemented by calling ScalaRunTime._toString(this) which accepts Product instances. Instead, I would like to suggest the compiler will generate code for toString similar to how code is generated for the equals method (btw, why isn't there a ScalaRunTime._equals method?) |
@paulp said: |
Ittay Dror (ittayd) said: "The problem with the current implementation is that it adds a rather heavyweight method to every case class. This is a lot of additional code for not a lot of appreciable gain" But I think toString has 2 differences:
So if I have: case class Person(name: String, age: Int) the toString can be: public String toString() { return ScalaRunTime..MODULE$$._toString(this, "name", "age");} where _toString is: def _toString(p: Product, names: String*) |
@paulp said: |
@SethTisue said: |
Tony Sloane (asloane) said: |
@SethTisue said: |
@paulp said: |
@retronym said: |
@retronym said: With 2.10.0 you will be able to add: override def toString = myCaseClassToString(this) Where If the research into macro annotations bears fruit, you could shorten this to: @myCaseToString
case class Person(...) But we can't make any promises about that feature. Unfortunately that reflection/macro API is still marked as experimental for 2.10.x, but you might find this sort of use case compelling enough to live with the possibility of a little flux. |
@etorreborre said: import scala.reflect.macros.blackbox._
import scala.language.experimental._
object ToString {
def toStringWithNames: String = macro toStringWithNamesImpl
def toStringWithNamesImpl(c: Context): c.Tree = {
import c.universe._
// class for which we want to display toString
val klass = c.internal.enclosingOwner.owner
// we keep the getter fields created by the user
val fields: Iterable[c.Symbol] = klass.asClass.toType.decls
.filter(sym => sym.isMethod && sym.asTerm.isParamAccessor) // we should do more filtering here
// print one field as <name of the field>+"="+fieldName
def printField(field: Symbol) = {
val fieldName = field.name
q"""${fieldName.decoded.toString}+${"="}+this.$field"""
}
val params = fields.foldLeft(q"${""}")((res, acc) => q"${printField(acc)} + $res")
// print the class and all the parameters with their values
q"this.productPrefix + ${"("} + $params + ${")"}"
}
}
==> sandbox/test.scala <==
case class Point(x: Int) {
override def toString = ToString.toStringWithNames
}
object Test extends App {
println(Some(Point(1)).toString)
}
% scalac-hash v2.11.2 sandbox/macro.scala && scalac-hash v2.11.2 sandbox/test.scala && scala-hash v2.11.2 Test
warning: there was one deprecation warning; re-run with -deprecation for details
one warning found
Some(Point(x=1))
|
Dean Hiller (deanhiller) said: |
Dean Hiller (deanhiller) said: |
Pedro Larroy said: import scala.reflect.ClassTag object CaseClassBeautifier { def nice[T:TypeTag](x: T)(implicit classTag: ClassTag[T]) : String = { |
It would have been more readable for Foo's toString to print something like:
The text was updated successfully, but these errors were encountered: