views:

918

answers:

3

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.

+5  A: 

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.

andri
That makes a lot of sense and is basically what I had been guessing. However, I did not find the implicit converter. Thanks for pointing it out. So basically, this is a major concession to Java interoperability, sacrificing some type soundness.
Johannes Stiehler
No type soundness is lost. Implicit conversion is just the compiler inserting a function call, something like val z: Seq[Char] = string2Seq(x)
James Iry
+2  A: 

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 {
     ...
   }
 }
Jorge Ortiz
+6  A: 

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.

extempore
The concession is that String cannot directly inherit from Seq[Char] since it is a typedef to the Java type.
Johannes Stiehler
Sorry, you're right that there is a concession of sorts (in fact scala is swimming with them) just not that there is any loss of type soundness, which means something specific and is not affected here.
extempore