Scala's dual string interpolation not working with escaped characters

64 Views Asked by At

I am trying to use the dual/reverse string interpolation to destructure a string into values, but I'm hitting issues if the string contains escaped characters like '\t' or '\n'.

For reference, I'm talking about this feature added in scala 2.13 by Li Haoyi in 7387.

This example from the PR works:

val s"Hello, $name" = "Hello, James"
println(name)  // "James"

however putting a '\t' or '\n' into it breaks it:

// '\t'
val s"Hello\t$name" = "Hello\tJames"
// scala.MatchError: Hello James (of class java.lang.String)

// '\n'
val s"Hello\n$name" = "Hello\nJames"
// scala.MatchError: Hello     <---- note error is different to others

// '\r'
val s"Hello\r$name" = "Hello\rJames"
// James (of class java.lang.String)  <---- note weird error that gets thrown here

// '\"'
val s"Hello\"$name" = "Hello\"James"
// scala.MatchError: Hello"James (of class java.lang.String)

// '\\'
val s"Hello\\$name" = "Hello\\James"
// scala.MatchError: Hello\James (of class java.lang.String)

The above was run on ammonite for scala 2.13 on WSL with java 8. I get similar issues in scala 3 and in sbt projects.

This isn't a blocker for me, but I find this feature useful and wanted to understand it better. The only docs I can find for this feature are on the original PR and a very brief mention in the scala 2.13 release notes.

Some questions:

  1. Is this intended behaviour or a bug or undefined? The PR doesn't define the behavior for these kinds of edge cases.
  2. Are there any known work arounds?
  3. What is the official name for this feature? On the PR Haoyi calls it the "dual of the simple string interpolator". Knowing its proper name would help me search for it.
  4. Are there any other official docs on this?

It feels like a bug because normal interpolation supports escapes and this feature is the "dual" of it:

val name = "James"

s"Hello\t$name"
// "Hello\tJames"

Thanks!

1

There are 1 best solutions below

0
rmin On
  1. Is this intended behaviour or a bug or undefined? The PR doesn't define the behavior for these kinds of edge cases.

This was deemed a bug - see issue 12893.

It was fixed quickly - see PR 10570.


  1. Are there any known work arounds?

Now that the bug is fixed, workarounds won't be needed much.

But for the sake of completeness, as suggested by @Gaël, a regex could be used:

// Scala 2.13
val afterHello = "Hello\t(.*)".r

val afterHello(name) = "Hello\tJames"
// `name` set to "James"

In scala 3 you'll get a compiler warning about the match not being exhaustive. To remove that, add unchecked like below:

// Scala 3
val afterHello(name) = "Hello\tJames": String @ unchecked

Or use trusty split:

val Array(_, name) = "Hello\tJames".split('\t')

This one doesn't need unchecked for some reason.


  1. What is the official name for this feature? On the PR Haoyi calls it the "dual of the simple string interpolator". Knowing its proper name would help me search for it.

I asked about this in issue 12893. Seth said:

At some level it's just a method and not a "feature"; string interpolation is the feature, individual interpolators are methods.


  1. Are there any other official docs on this?

Other than the original PR, there doesn't seem to be any official docs.

Issue 12893 did links to some official docs about how interpolation patterns gets transformed. These were helpful for general background, but doesn't relate specifically to this feature.