scala - trying to print overridden toString method
Asked Answered
E

4

10

the bellow code :

scala> class A {
 |     def hi = "Hello from A"
 |     override def toString = getClass.getName
 | }
defined class A

scala> val a = new A()
a: A = A

scala> a.toString
res10: String = A

scala> println(s"${a.toString}")
$line31.$read$$iw$$iw$A

It is printing ok when using a.toString expression, not when using println(s"${a.toString}"). The problem is getClass.getName. In other cases it works nice.

Thanks in advance for any help

Eade answered 15/9, 2016 at 16:33 Comment(5)
this problem is only with Scala repl. on Ammonite repl everything works finePentosan
Ammonite REPL output scala> class A { override def toString = getClass.getName } defined class A scala> val a = new A() a: A = $sess.cmd0$A scala> a.toString res2: String = "$sess.cmd0$A" scala> println(s"""${a.toString}""") $sess.cmd0$APentosan
This definitely looks like a repl caveatNut
Yes ... the problem is REPL .... it's a problem as it doesn't look natural behaivor and the result is not the expected oneEade
If we run this code as a online programa (scala myprog.scala) the we get the spected result. So the problem is in REPL class A { override def toString: String = getClass.getName } object Date { def main(args: Array[String]) { println(new A().toString) } }Eade
P
6

REPL filters its output to hide template wrappings.

$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.

scala> class A
defined class A

scala> val a = new A
a: A = A@4926097b

scala> a.getClass
res0: Class[_ <: A] = class A

scala> $intp.isettings.
allSettings   deprecation   deprecation_=   maxAutoprintCompletion   maxPrintString   toString   unwrapStrings

scala> $intp.isettings.unwrapStrings = false
$intp.isettings.unwrapStrings: Boolean = false

scala> a.getClass
res1: Class[_ <: A] = class $line3.$read$$iw$$iw$A

You can also compare output clipping:

scala> (1 to 1000).mkString
res2: String = 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629...
scala> println((1 to 1000).mkString)
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000

Scroll right to see the ellipsis on the first line.

Philoprogenitive answered 15/9, 2016 at 19:0 Comment(2)
$intp.isettings.unwrapStrings = false And then: scala> println(new A) //prints $line3.$read$$iw$$iw$ANut
@Nut Not sure what you're demonstrating. As I showed, REPL filters its own output, not anything else.Philoprogenitive
E
5

Since names of classes inside REPL are different, REPL needs to convert internal names back. It does it well enough when displaying strings, but fails when string is passed to an external method, e.g. println or toList:

scala> a.toString
res1: String = A

scala> a.toString.toList
res2: List[Char] = List($, l, i, n, e, 4, ., $, r, e, a, d, $, $, i, w, $, $, i, w, $, A)

scala> "$line4.$read$$iw$$iw$A"
res3: String = A
Experimentation answered 15/9, 2016 at 18:20 Comment(5)
What is interesting is val x = a.toString; println(x) also prints $line3.$read$$iw$$iw$ANut
But, List(a.toString) gives List(A)Multiphase
@Multiphase Because List(a.toString) is a List[String], and REPL knows that String should be replaced when needed.Experimentation
@Nut When you display x in REPL it will replace x's value with A, println doesn't know about replacement. The real value of x is $line3.$read$$iw$$iw$A and won't change when copying.Experimentation
To be clear, "convert internal names back" really means "strip strings that look like internal cruft from output", which is more crude than somehow detecting that toString results in an internal string and then subverting it.Philoprogenitive
M
4

Run the scala repl using: scala -Xprint:parser

Then run the successive commands. The output $line3.$read$$iw$$iw$A represents the path to the A object. $line is a package, $read and $iw are objects under which the object A is nested.

For the case of println(s"${a.toString}")

scala> println(s"${a.toString}")
[[syntax trees at end of                    parser]] // <console>
package $line5 {
  object $read extends scala.AnyRef {
    def <init>() = {
      super.<init>();
      ()
    };
    object $iw extends scala.AnyRef {
      def <init>() = {
        super.<init>();
        ()
      };
      import $line3.$read.$iw.$iw.A;
      import $line4.$read.$iw.$iw.a;
      object $iw extends scala.AnyRef {
        def <init>() = {
          super.<init>();
          ()
        };
        val res0 = println(StringContext("", "").s(a.toString))
      }
    }
  }
}

[[syntax trees at end of                    parser]] // <console>
package $line5 {
  object $eval extends scala.AnyRef {
    def <init>() = {
      super.<init>();
      ()
    };
    lazy val $result = $line5.$read.$iw.$iw.res0;
    lazy val $print: String = {
      $line5.$read.$iw.$iw;  
      ""   <-- // SOMETHING OFF HERE! NO OUTPUT STRING BEING GENERATED?
    }
  }
}

$line3.$read$$iw$$iw$A

Now for the case of a.toString:

scala> a.toString
[[syntax trees at end of                    parser]] // <console>
package $line6 {
  object $read extends scala.AnyRef {
    def <init>() = {
      super.<init>();
      ()
    };
    object $iw extends scala.AnyRef {
      def <init>() = {
        super.<init>();
        ()
      };
      import $line3.$read.$iw.$iw.A;
      import $line4.$read.$iw.$iw.a;
      object $iw extends scala.AnyRef {
        def <init>() = {
          super.<init>();
          ()
        };
        val res1 = a.toString
      }
    }
  }
}

[[syntax trees at end of                    parser]] // <console>
package $line6 {
  object $eval extends scala.AnyRef {
    def <init>() = {
      super.<init>();
      ()
    };
    lazy val $result = $line6.$read.$iw.$iw.res1;
    lazy val $print: String = {
      $line6.$read.$iw.$iw;  // *CORRECTLY GENERATES THE RESULT STRING.*
      "".$plus("res1: String = ").$plus(scala.runtime.ScalaRunTime.replStringOf($line6.$read.$iw.$iw.res1, 1000))
    }
  }
}

res1: String = A
Multiphase answered 15/9, 2016 at 18:38 Comment(6)
This does not answer the question. a.toString prints a. println(a.toString) prints $line3....Nut
As seen in the $eval objects (which generates the result string to be shown in the repl) for both the cases, the repl is generating the string to be shown differently for the two cases. Not sure why its doing that yet.Multiphase
Thank you, I can see where the problem is. The problem is not fixed but clearly I can see it's locationEade
Normally, $eval.$print is a string representation of the computed value. But if the result type is Unit, it doesn't output a string. Try scala> () at the prompt. Not exactly sure how this helped the OP, but SO works in mysterious ways.Philoprogenitive
@som-snytt: so in the above output, val res0 = println(StringContext("", "").s(a.toString)) is the statement responsible for the print to console in the first case?Multiphase
Yes, that's just the code you entered. If you don't assign it to a variable, it will assign to a synthetic like res0. The REPL prints the value of $print, which lazily evaluates $read.Philoprogenitive
B
-1

It is the way REPL is compiling A. In a simple app like below there are no issues
Each line in the REPL is wrapped into it's own package.. and that auto generated package name is what you see prepended to class name A.

object ScalaApp extends App {

      class A {
        def hi = "Hello from A"
        override def toString = getClass.getName
      }

      val a = new A()

      println(a.toString)

      println(s"${a.toString}")
    }
Benedicto answered 15/9, 2016 at 18:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.