Problem rewriting scala method post upgrade to scala 2.12 (from 2.11)

Viewed 413

I have the following small but complex method in my project:

private def indent ( s : String )
  = s.lines.toStream match {
    case h +: t =>
      ( ("- " + h) +: t.map{"| " + _} ) mkString "\n"
    case _ => "- "
  }

After upgrading my project from Scala 2.11 to 2.12, it would no longer compile. Error:

CaseClassString.scala:14: value toStream is not a member of java.util.stream.Stream[String]

I tried rewriting like this:

private def indent ( s : String )
  = Stream(s.lines) match {
    case h +: t =>
      ( ("- " + h) +: t.map{"| " + _} ) mkString "\n"
    case _ => "- "
  }

But it is not working.

This method was found in the following project: https://github.com/nikita-volkov/sext

The function would transform a string like:

metricResult: column: value: city
function: density
value: metricValue: 0.1

to:

- metricResult: column: value: city
| - function: density
| - value: metricValue: 0.1

Anyone have other ideas about how to rewrite this method for Scala 2.12?

3 Answers

I suspect that you've also upgraded your JVM from Java 8 to Java 11 (or are using code written to run on Java 8 on Java 11). Java 11 added a lines method to String which results in a java.util.Stream[String]. On Java 8, there's no lines method for String which means that the Scala compiler can implicitly convert a String to scala.collection.immutable.StringOps which has a lines method with result type Iterator[String].

The trick here is to be explicit that you want to use StringOps.lines instead of String.lines, so something like

val lines = (s: scala.collection.immutable.StringOps).lines
lines.toStream match {
  // etc.
}

It seems like that you not only upgraded Scala but also upgraded Java version. The error is simple to understand if you simply look at changes related to String for both Java and Scala.

import scala.collection.immutable.StringOps

def indent(s : String): String =
  (s: StringOps).lines.toStream match {
    case h +: t =>
      ( ("- " + h) +: t.map{"| " + _} ) mkString "\n"
    case _ => "- "
  }

Or, if you are working with Java 11 and don't really need Stream then,

def indent(s : String): String =
  s.lines.toArray.toList match {
  case h :: t =>
    val indented = ("- " + h) :: t.map{"| " + _}
    indented.mkString("\n")
  case _ => "- "
}

Very similar to Andrey's solution, but working:

def indent(s: String) = s.linesIterator.mkString("- ", "\n| - ", "")

Code run at scatie.

Related