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 :: Nil
≡ Nil.::(3)
, as
val l: List[Int] = ( ( Nil.::(3) ).::(2) ).::(1)