Search code examples
scalamatchingextractor

Why doesn't Scala optimize calls to the same Extractor?


Take the following example, why is the extractor called multiple times as opposed to temporarily storing the results of the first call and matching against that. Wouldn't it be reasonable to assume that results from unapply would not change given the same string.

object Name {
  val NameReg = """^(\w+)\s(?:(\w+)\s)?(\w+)$""".r

  def unapply(fullName: String): Option[(String, String, String)] = {
    val NameReg(fname, mname, lname) = fullName
    Some((fname, if (mname == null) "" else mname, lname))
  }
}

"John Smith Doe" match {
  case Name("Jane", _, _) => println("I know you, Jane.")
  case Name(f, "", _) => println(s"Hi ${f}")
  case Name(f, m, _) => println(s"Howdy, ${f} ${m}.")
  case _ => println("Don't know you")
}

Solution

  • Wouldn't it be reasonable to assume that results from unapply would not change given the same string.

    Unfortunately, assuming isn't good enough for a (static) compiler. In order for memoizing to be a legal optimization, the compiler has to prove that the expression being memoized is pure and referentially transparent. However, in the general case, this is equivalent to solving the Halting Problem.

    It would certainly be possible to write an optimization pass which tries to prove purity of certain expressions and memoizes them iff and only iff it succeeds, but that may be more trouble than it's worth. Such proofs get very hard very quickly, so they are only likely to succeed for very trivial expressions, which execute very quickly anyway.