Scala vs Java toUpperCase/toLowerCase

GreyCat :

Scala borrows Java String methods like toUpperCase/toLowerCase.

However, the way it does so is not very consistent:

  • Scala on JVM stick close to Java semantics, thus:
    • toUpperCase() is locale-sensitive and sticks to default locale (giving you infamous i → İ problem in Turkish locale)
    • to avoid that and keep locale-insensitive (en_US / C-like) process, you need to specifically do toUpperCase(Locale.ROOT)
  • Scala.JS does not implement a concept of Locale, thus:
    • toUpperCase() works in locale-insensitive manner
    • toUpperCase(Locale locale) method is effectively not available in ScalaJS

How do I implement locale-insensitive case conversion that will work in Scala on both JVM/JS?

I can think of several ways, all of them as ugly:

Method 1: My own implementation

Implement my own toUpperCase for specifically 26 ASCII characters of English alphabet.

Method 1.1: My own implementation using Scala chars

Basically the same, but at least reuse Scala toUpper to convert individual chars.

Method 2: Interface

Implement something like

trait CaseChangeOps {
  def toUpperCase(s: String): String
}

object Main {
  var caseChanger: CaseChanger
}

// whenever I want to use it, do it like that:
Main.caseChanger.toUpperCase("like this") // => "LIKE THIS"

in shared code, and then in JS have:

object CaseChangerJs {
  def toUpperCase(s: String): String = s.toUpperCase
}

object MainJs {
  Main.caseChanger = CaseChangerJs
}

... and in JVM:

object CaseChangerJvm {
  def toUpperCase(s: String): String = s.toUpperCase(Locale.ROOT)
}

object MainJvm {
  Main.caseChanger = CaseChangerJvm
}

Method 3: bring external scala-java-locales

There is a distinct 3rd party library scala-java-locales, which is listed as ScalaJS-compatible, and can be used to augument ScalaJS.

Looks like a massive overkill, though, as I literally only need locale-insensitive case conversions, not the whole thing for all possible locales.

Any better ideas?

Alexey Romanov :

The standard approach is close to your method 2, but much simpler. In shared code you just call

Platform.toUpperLocaleInsensitive(string)

which has different implementations on JVM and JS:

// JVM
object Platform {
  def toUpperLocaleInsensitive(s: String) = s.toUpperCase(Locale.ROOT)

  // other methods with different implementations
}

// JS
object Platform {
  def toUpperLocaleInsensitive(s: String) = s.toUpperCase()

  // other methods with different implementations
}

See the description of a similar case in Hands-on Scala.js.

This works because shared code doesn't need to compile by itself, only together with platform-specific code.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=415566&siteId=1