Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching a String as Seq[Char]

In Scala it is possible formulate patterns based on the invididual characters of a string by treating it as a Seq[Char].

An example of this feature is mentioned in A Tour of Scala

This is the example code used there:

object RegExpTest1 extends Application {
 def containsScala(x: String): Boolean = {
   val z: Seq[Char] = x
   z match {
      case Seq('s','c','a','l','a', rest @ _*) =>
                println("rest is "+rest)
                true
      case Seq(_*) =>
                false
   }
 }

}

The problem I have with this is the third line of the snippet:

val z: Seq[Char] = x

Why is this sort of cast necessary? Shouldn't a String behave like a Seq[Char] under all circumstances (which would include pattern matching)? However, without this conversion, the code snippet will not work.

like image 965
Johannes Stiehler Avatar asked Apr 11 '09 18:04

Johannes Stiehler


3 Answers

There is some real abuse of terminology going on in the question and the comments. There is no cast in this code, and especially "So basically, this is a major concession to Java interoperability, sacrificing some type soundness" has no basis in reality.

A scala cast looks like this: x.asInstanceOf[Y].
What you see above is an assignment: val z: Seq[Char] = x

This assignment is legal because there is an implicit conversion from String to Seq[Char]. I emphasize again, this is not a cast. A cast is an arbitrary assertion which can fail at runtime. There is no way for the implicit conversion to fail.

The problem with depending on implicit conversions between types, and the answer to the original question, is that implicit conversions only take place if the original value doesn't type check. Since it's perfectly legal to match on a String, no conversion takes place, the match just fails.

like image 86
psp Avatar answered Oct 19 '22 02:10

psp


Not 100% sure if this is correct, but my intuition says that without this explicit cast you would pattern match against java.lang.String, which is not what you want.

The explicit cast forces the Scala compiler to use Predef.stringWrapper implicit conversion; thus, as RichString extends Seq[Char], you are able to do a pattern match as if the string were a sequence of characters.

like image 31
andri Avatar answered Oct 19 '22 01:10

andri


I'm going to echo everything that andri said. For interoperability, Scala strings are java.lang.Strings. In Predef, there's an implicit conversion from String to RichString, which implements Seq[Char].

A perhaps nicer way of coding the pattern match, without needing an intermediate val z to hold the Seq[Char]:

def containsScala(x: String): Boolean = {
  (x: Seq[Char]) match {
    ...
  }
}
like image 31
Jorge Ortiz Avatar answered Oct 19 '22 03:10

Jorge Ortiz