views:

101

answers:

2

Hi all, regarding the following scala code, functions m2a and m2b apparently differ only by the case of the parameter, ie abc vs Abc. This seems to make some difference in the result as per example below. When running it with a recent 2.8 compiler, it results in the following (I would have expected all true). Any insights would be appreciated.

m1=true
m2a=true
m2b=false
m3=true

code

package sample

import scala.xml._

object ParamTest extends Application {

  def m1(n:Node, abc:String):Boolean = {
    n == <id>{Text(abc)}</id>
  }

  def m2a(n:Node, Abc:String):Boolean = n match {
    case <id>{Text(Abc)}</id> => true
    case _ => false;
  }

  // why does this one not work?
  def m2b(n:Node, abc:String):Boolean = n match {
    case <id>{Text(abc)}</id> => true
    case _ => false;
  }

  def m3(n:Node, abc:String):Boolean = n match {
    case Elem(_,"id",_,_, c @_ *) => {
      c contains Text(abc)
    }
  }

  def runner(n:Node, f:(Node, String)=>Boolean):Boolean = {
    f(n, "x") && !f(n, "y") && !f(n, "");
  }

  val x = <id>x</id>

  println("m1="+runner(x, m1));
  println("m2a="+runner(x, m2a));
  println("m2b="+runner(x, m2b));
  println("m3="+runner(x, m3));
}
+4  A: 

The trick here is in how Scala handles variables in case expressions. Lowercase variables in case expressions are taken by the compiler to introduce new variables, which are then pattern matched against. Thus in method m2b, the method parameter "abc" is actually unused. The case expression variable "abc" will match any string, since it is not otherwise constrained. Thus "y" is successfully matched in the first case of m2b. Uppercase variables in case expressions do not introduce new variables, so in m2a the match behaves as you expected.

The easiest way to match against the value of a lowercase variable is to wrap it in backquotes. Thus

def m2b(n:Node, abc:String):Boolean = n match {
    case <id>{Text(`abc`)}</id> => true
    case _ => false;
  }

will give you the results you expected.

Dave Griffith
+4  A: 

In pattern matching, identifiers in the pattern that start with a lower-case letter are taken to be free pattern variables that can be bound to values in the target of the match. Those that start with upper-case letters are so-called stable identifiers and must already be bound in the match expression's context and the value of that binding must equal the subexpression of the match target at the point in that value corresponding to that stable identifier's placement within the pattern expression.

Additionally, and relevant in this particular example, pattern variables (the lower-case names) will shadow any existing binding of the same name that is in effect in the context of the match expression (including the expression supplying the match target value).

Randall Schulz