Monday, January 23, 2012

String Interpolation on Scala 2.10

One of the Scala Improvement Proposals for Scala 2.10 is String Interpolation. It has recently been added to trunk, behind the -Xexperimental flag, and I have started playing with it. At first, I stumbled upon bugs and limitations of its current implementation relative to the proposal, but I finally got something working.

To be clear: the interpolation works fine, in both of the provided forms (with and without formatting). As usual with Scala, it's the possibility of replicating the functionality for my own purposes that gets me excited. I usually explain the whys and the hows of my code, but in this case a simple paste says it all, imho.

dcs@ayanami:~/github/scala (master)$ scala -Xexperimental
Welcome to Scala version 2.10.0.rdev-4232-2012-01-23-g9a20086 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).
Type in expressions to have them evaluated.
Type :help for more information.

scala> case class StringContext(parts: String*) {
     |   object matching {
     |     def unapplySeq(s: String): Option[Seq[String]] = {
     |       val re = (parts map ("\\Q" + _ + "\\E") mkString ("^", "(.*?)", "$")).r
     |       re findFirstMatchIn s map (_.subgroups)
     |     }
     |   }
     |   def s(args: Any*) = scala.StringContext(parts: _*).s(args: _*)
     | }
defined class StringContext

scala> "23/01/2012" match { case matching"$day/$month/$year" => s"$month-$day-$year" }
res0: String = 01-23-2012

Monday, January 9, 2012

Adding methods to Scala Collections

I don't like getting much involved in these Scala flame wars, but this recent article left me a bit irked. At some point, the following statement is made:

"it is impossible to insert a new method that behaves like a normal collection method. "

So, for the record, that is just not true. Here's an implementation for the filterMap method:

import scala.collection._
import generic.CanBuildFrom
import mutable.Builder
class FilterMap[A, C <: Seq[A]](xs: C with SeqLike[A, C]) {
     def filterMap[B, That](f: A => Option[B])
                     (implicit cbf: CanBuildFrom[C, B, That]): That = {
       val builder: Builder[B, That] = cbf()
       xs foreach { x => val y = f(x); if (y.nonEmpty) builder += y.get }
implicit def toFilterMap[A, C <: Seq[A]](xs: C with SeqLike[A, C]): FilterMap[A, C] = new FilterMap[A, C](xs)

Is this what the author wanted? No. He wanted too add a method that behaved like a normal collection method to something that isn't a collection. This is so crazy that, not surprisingly, people are misunderstanding him.

Now, one may come up and say that Scala does do that (add methods to stuff that are not collection), with String and Array. Yes, it does, and it does so by creating a completely new class with all these methods for each of them. Rest assured that if I create a completely new class for each one, I can add filterMap to String and Array too.