7

Is it there an equivalent of Pythons repr function in scala?

Ie a function which you can give any scala object an it will produce a string representation of the object which is valid scala code.

eg:

val l = List(Map(1 -> "a"))

print(repr(l))

Would produce

List(Map(1 -> "a"))
Todd O'Bryan
  • 2,234
  • 17
  • 30
Mark
  • 467
  • 3
  • 14
  • 5
    I think this makes more sense in a more dynamic language as python since you could later `eval` that string and do something with it – Pablo Fernandez Oct 21 '11 at 15:15
  • 2
    I don't think such a feature really makes sense, since Scala is a statically typed language. I suppose you could mix a `#toSource()` method into any class you create, but it seems to me like the only reason you'd do this is for educational (or maybe debugging purposes). – Jack Leow Oct 21 '11 at 15:15
  • Yes.. I wont it for debugging. Thats what I use it for in python too. – Mark Jan 03 '12 at 09:09
  • I personnally use such a feature to compile hand-made games, as an intermediate representation. So even if there is no eval, it can be used to create scala code for further reuse. – Mikaël Mayer May 17 '13 at 07:43

4 Answers4

6

There is mostly only the toString method on every object. (Inherited from Java.) This may or may not result in a parseable representation. In most generic cases it probably won’t; there is no real convention for this as there is in Python but some of the collection classes at least try to. (As long as they are not infinite.)

The point where it breaks down is of course already reached when Strings are involved

"some string".toString == "some string"

however, for a proper representation, one would need

repr("some string") == "\"some string\""

As far as I know there is no such thing in Scala. Some of the serialisation libraries might be of some help for this, though.

Debilski
  • 66,976
  • 12
  • 110
  • 133
  • The toString methods tend to not produce compilerble output. eg List(1 -> "a") gives you List[(Int, java.lang.String)] = List((1,a)) – Mark Oct 21 '11 at 15:03
  • Yep. True. It’s the strings. With only integers it would work, though. – Debilski Oct 21 '11 at 15:10
3

Based on the logic at Java equivalent of Python repr()?, I wrote this little function:

object Util {
  def repr(s: String): String = {
    if (s == null) "null"
    else s.toList.map {
      case '\0' => "\\0"
      case '\t' => "\\t"
      case '\n' => "\\n"
      case '\r' => "\\r"
      case '\"' => "\\\""
      case '\\' => "\\\\"
      case ch if (' ' <= ch && ch <= '\u007e') => ch.toString
      case ch => {
        val hex = Integer.toHexString(ch.toInt)
        "\\u%s%s".format("0" * (4 - hex.length), hex)
      }
    }.mkString("\"", "", "\"")
  }
}

I've tried it with a few values and it seems to work, though I'm pretty sure sticking in a Unicode character above U+FFFF would cause problems.

Community
  • 1
  • 1
Todd O'Bryan
  • 2,234
  • 17
  • 30
2

If you deal with case classes, you can mix in the following trait StringMaker, so that calling toString on such case classes will work even if their arguments are strings:

trait StringMaker {
  override def toString = {
    this.getClass.getName + "(" +
    this.getClass.getDeclaredFields.map{
      field =>
        field.setAccessible(true)
        val name = field.getName
        val value = field.get(this)
        value match {
          case s: String => "\"" + value + "\"" //Or Util.repr(value) see the other answer
          case _ => value.toString
        }
    }
    .reduceLeft{_+", "+_} +
    ")"
  }
}
trait Expression
case class EString(value: String, i: Int) extends Expression with StringMaker
case class EStringBad(value: String, i: Int) extends Expression //w/o StringMaker
val c_good = EString("641", 151)
val c_bad = EStringBad("641", 151)

will result in:

c_good: EString = EString("641", 151)
c_bad: EStringBad = EStringBad(641,151)

So you can parse back the firsst expression, but not the first one.

Mikaël Mayer
  • 10,425
  • 6
  • 64
  • 101
  • 2
    Interesting suggestions. Could we do something with macros now we have them... should be abel to do it without reflection? – Mark May 17 '13 at 09:20
  • That's very nice. I'd probably have put the .repr() as a separate function so you could still get the .toString() but also get the .repr() if you wanted it. – Todd O'Bryan May 27 '13 at 21:18
  • 1
    Actually, I didn't notice this before, but I don't think your code will work if the `String` value contains quotation marks or other weird characters. In that case, you'd have to use something like `Util.repr(value)` that I wrote above. – Todd O'Bryan Jun 19 '13 at 02:55
0

No, there is no such feature in Scala.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681