noodling towards a functional brain

Friday, February 05, 2010

Trick of the day

James Iry just mentioned something I'd never noticed before in #scala:
scala> def f(i: Int, x: Int) = i match { case `x` => println("x!"); case _ => println("nope") }
f: (i: Int,x: Int)Unit

scala> f(1, 1)
x!

scala> f(1, 2)
nope
That's one of those things that I'd idly wondered how to do, but hadn't had a use case so hadn't really gone looking. Good to know it's possible and simple... and more or less makes sense. More or less. Actually, I guess I'm kind of glad that the following doesn't compile:
scala> def f(i: Int) = i match { case `yield` => println(`yield`) }                           
<console>:4: error: not found: value yield
       def f(i: Int) = i match { case `yield` => println(`yield`) }
I can live with the restriction as not being able to use a reserved word for a variable on the lhs of a pattern match, though it does make for a weird inconsistency:
scala> val (`yield`, x) = (1, 1)
<console>:4: error: not found: value yield
       val (`yield`, x) = (1, 1)
            ^

scala> val `yield` = 1
yield: Int = 1
Chalk up one more to the box of "pain points caused by using pattern matching for parallel assignment."

11 comments:

  1. scala> def f(`yield` : Int) = 5 match { case `yield` => "yup"; case _ => "nope"}
    f: (yield: Int)java.lang.String

    scala> f(5)
    res14: java.lang.String = yup

    ReplyDelete
  2. Anonymous9:00 AM

    Ha! A step towards Prolog's unification, almost, perhaps :)

    ReplyDelete
  3. Anonymous8:43 AM

    Hello!

    Would be happy for a little background knowledge, why
    this is possible :D

    best regards

    ReplyDelete
  4. Anonymous, can you clarify your question?

    ReplyDelete
  5. Anonymous12:08 PM

    Hello,

    I really trying to see why the case statement is matching the x :). Dont know why but I dont get it :)

    best regards

    ReplyDelete
  6. Anonymous: Those are backquotes - in Scala, you ordinarily use backquotes to use what would otherwise be a reserved word as a legal identifier. Ordinarily, a bare token on the left hand side of the arrow in the case clause of a match expression denotes a variable to be bound; however, when you backquote that token it becomes a reference to a variable in the enclosing scope. Hence, in the first example the value of x within the function is 1, and the case evaluates as 1 == 1.

    ReplyDelete
  7. ianam2:07 PM

    There's no inconsistency at all ... did you even read the error messages? This works:

    scala> val `yield` = 1
    yield: Int = 1

    scala> val (`yield`, x) = (1, 1)
    x: Int = 1

    And of course this does not:

    scala> val yield = 1
    :1: error: illegal start of simple pattern
    val yield = 1
    ^

    scala> val (yield, x) = (1, 1)
    :1: error: illegal start of simple pattern
    val (yield, x) = (1, 1)

    ReplyDelete
  8. ianam2:10 PM

    "however, when you backquote that token it becomes a reference to a variable in the enclosing scope"

    Just as if it didn't start with a lowercase letter.

    ReplyDelete
  9. ianam: you'll notice that you defined `yield` in the REPL session *before* attempting the extraction from the tuple. Since such an identifier was defined in scope, then the pattern match succeeded; if you simply enter the second line as the *first* statement in a REPL session, it will not compile.

    The inconsistency lies in the fact that a backquoted variable in a pattern match will perform an equality check so long as such a variable is in scope (which is what it did in your session) *unless* the backquoted token is a keyword, in which case it does not cause a new variable to be defined in this context.

    ReplyDelete
  10. Thank you for sharing this information and Very good looking blog on

    One Plus X Case

    ReplyDelete

About Me

My photo
aspiring to elegant simplicity