views:

116

answers:

1

I have a case class

case class ~[a,b](_1:a, _2:b)

When I want to do pattetn matching

new ~("a", 25) match{
  case "a" ~ 25 =>
}

I can use it this way because "a" ~ 25 and ~("a", 25) are equivalent. But if I want to match new ~("a", new ~("b", 25)) by {case "a" ~ "b" ~ 25 => } troubles begin. I understand that this statements aren't equivalent. So, how new ~("a", new ~("b", 25)) can be presented? By what rules?

+9  A: 

This works:

new ~("a", new ~("b", 25)) match {
  case "a" ~ ("b" ~ 25) =>
}

So, you’ll have to put the parentheses the same way they are in the initial clause. Otherwise the tilde is left-associative, therefore the type of the pattern will be different and it won’t compile.

case "a" ~ "b" ~ 25

is the same as

case ("a" ~ "b") ~ 25

which would be wrong in your case.

Appendix

You can get right-associativity by having a colon as the last character in your class/method name. The following compiles and matches without parentheses (and you can drop the new as the compiler won’t be confused anymore by $tilde$colon):

case class ~:[a,b](_1:a, _2:b)

~:("a", ~:("b", 25)) match {
  case "a" ~: "b" ~: 25 =>
}

Responses

1) Without the new keyword, the case class ~ is shadowed by unary_~ which gives the bitwise negation of the argument. An expression like ~ 2 is internally evaluated to unary_~(2) and the same goes for the case of ~ ("a", 1) – however unless you define unary_~ on that tuple, this will give an error. With the new keyword you advise the compiler to explicitly look for a class with that name, so it won’t get confused. (Technically, you could work around this by using $tilde("a", 1) which is the internal name for your case class ~, but since this is a compiler detail, you should probably not rely on it.)

2&3) The right-associativity is referenced in the Scala Language Specification. Section ‘Infix Operations’

The associativity of an operator is determined by the operator’s last character. Operators ending in a colon ‘:’ are right-associative. All other operators are left-associative.

By the way, right-associativity is the trick that allows for creating lists with Nil. (Nil is the empty List and has the right-associative concatenation operator :: defined.)

val l: List[Int] = 1 :: 2 :: 3 :: Nil

which is evaluated as follows

val l: List[Int] = (1 :: (2 :: (3 :: Nil)))

or, more precisely, since 3 :: NilNil.::(3), as

val l: List[Int] = ( ( Nil.::(3) ).::(2) ).::(1)
Debilski
I don't understand1)Why compiler is confused when class name is '~' and I don't put 'new' keyword?2)>>You can get right-associativity by having a colon as the last character in your class/method name. That's creepy :3 Where can I read about this unobvious behavior?
stub
See my additions.
Debilski