60

Scala has triple quoted strings """String\nString""" to use special characters in the string without escaping. Scala 2.10 also added raw"String\nString" for the same purpose.

Is there any difference in how raw"" and """""" work? Can they produce different output for the same string?

1
  • The critical insight I got from the answers below is that using the "s" interpolator combined with the "triple quote" interpolator enabled substitution in a static multi-lined template. I was on the verge of writing my own when I googled, saw @som-snytt's answer below and was SO excited. The way to use it is val template = s"""Hi there, $name! You have $amount credits remaining! Code: ${code}00""" The curly braces on the last parameter are required because of the immediately following alphanumeric characters. Commented May 26, 2019 at 19:19

2 Answers 2

79

Looking at the source for the default interpolators (found here: https://github.com/scala/scala/blob/2.11.x/src/library/scala/StringContext.scala) it looks like the "raw" interpolator calls the identity function on each letter, so what you put in is what you get out. The biggest difference that you will find is that if you are providing a string literal in your source that includes the quote character, the raw interpolator still won't work. i.e. you can't say

raw"this whole "thing" should be one string object"

but you can say

"""this whole "thing" should be one string object"""

So you might be wondering "Why would I ever bother using the raw interpolator then?" and the answer is that the raw interpolator still performs variable substitution. So

val helloVar = "hello"
val helloWorldString = raw"""$helloVar, "World"!\n"""

Will give you the string "hello, "World"!\n" with the \n not being converted to a newline, and the quotes around the word world.

6
  • Thanks, I missed the part in docs where it says that it also does interpolation.
    – ntn
    Commented Sep 2, 2014 at 22:30
  • 1
    For the record, the scaladoc does actually say what it does. scala-lang.org/files/archive/nightly/2.11.x/api/2.11.x/…*):String
    – som-snytt
    Commented Sep 2, 2014 at 23:19
  • 3
    Basically, you say that raw does what s does. I can s"""$literal string with substitution""". This does not explain the need for row anyway. Commented Jan 5, 2016 at 14:19
  • 1
    @ValentinTihomirov The difference is that the s interpolator still performs escaping since it is not aware that it is in triple quotes. som-snytt 's answer does a nice job of demonstrating and explaining this: stackoverflow.com/a/25633978/892445 Commented Jan 5, 2016 at 18:32
  • 1
    Here's a fun thing I just ran across. The $ character marks a variable in interpolation, and the end of a line or a string in regex. So triple quoting turns out to be better for regular expressions. Commented Feb 22, 2017 at 15:41
38

It is surprising that using the s-interpolator turns escapes back on, even when using triple quotes:

scala> "hi\nthere."
res5: String =
hi
there.

scala> """hi\nthere."""
res6: String = hi\nthere.

scala> s"""hi\nthere."""
res7: String =
hi
there.

The s-interpolator doesn't know that it's processing string parts that were originally triple-quoted. Hence:

scala> raw"""hi\nthere."""
res8: String = hi\nthere.

This matters when you're using backslashes in other ways, such as regexes:

scala> val n = """\d"""
n: String = \d

scala> s"$n".r
res9: scala.util.matching.Regex = \d

scala> s"\d".r
scala.StringContext$InvalidEscapeException: invalid escape character at index 0 in "\d"
  at scala.StringContext$.loop$1(StringContext.scala:231)
  at scala.StringContext$.replace$1(StringContext.scala:241)
  at scala.StringContext$.treatEscapes0(StringContext.scala:245)
  at scala.StringContext$.treatEscapes(StringContext.scala:190)
  at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
  at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
  at scala.StringContext.standardInterpolator(StringContext.scala:124)
  at scala.StringContext.s(StringContext.scala:94)
  ... 33 elided

scala> s"""\d""".r
scala.StringContext$InvalidEscapeException: invalid escape character at index 0 in "\d"
  at scala.StringContext$.loop$1(StringContext.scala:231)
  at scala.StringContext$.replace$1(StringContext.scala:241)
  at scala.StringContext$.treatEscapes0(StringContext.scala:245)
  at scala.StringContext$.treatEscapes(StringContext.scala:190)
  at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
  at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
  at scala.StringContext.standardInterpolator(StringContext.scala:124)
  at scala.StringContext.s(StringContext.scala:94)
  ... 33 elided

scala> raw"""\d$n""".r
res12: scala.util.matching.Regex = \d\d
2
  • 3
    That is indeed odd, and not what I would have assumed to be the case. Thanks for pointing it out. Commented Oct 19, 2015 at 0:44
  • 1
    I wish I could upvote this more than once. It just saved me several hours. I was getting ready to write my own implementation unaware that I could combine the "s" interpolator with the "triple quote" interpolator! I've been looking for this solution for over a year (and stupidly hard coded a masking tape and bailing wire solution several times). Commented May 26, 2019 at 19:23

Not the answer you're looking for? Browse other questions tagged or ask your own question.