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."

12 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
  11. Wonderful bloggers like yourself who would positively reply encouraged me to be more open and engaging in commenting.So know it's helpful.
    PHP Training in Chennai

    ReplyDelete

About Me

My photo
aspiring to elegant simplicity