I propose to migrate from bars to commas` as a way to separate pattern alternatives. I.e. instead of
x match { case A | B | C => ... }
use the syntax
x match { case A, B, C => ... }
The main reason to do the syntax switch is that it avoids an annoying feature interaction with union types. For instance, consider:
x match { case _: A | B => ... }
Is this a single pattern that tests whether x is of type A | B, or are these two patterns matching
either an x of type A or an x equal to the value B? The way it’s implemented now it is the second meaning, since that maintains backwards compatibility with Scala 2. But arguably the first interpretation is more natural, so people will be surprised that it does not work. To get the first meaning, they have to write
x match { case _: (A | B) => ... }
instead, but realizing this is not obvious. Switching from (|) to (,) avoids that problem.
I like it. I was wondering if we should use || instead of | for this purpose (this would also make && natural for combining patterns), but I was worried that something like case true || false would be too confusing. This syntax avoids that, however here’s a minor issue with it:
Right now, one can write:
object A
object B
val (A | B) = A: Any
And this couldn’t be replaced by either val (A, B) = A: Any or val A, B = A: Any since both of those things already mean something different (although I’d be happy to remove the val x,y,z = syntactic form from the language).
@Sciss It’s a pattern definition, you can write val List(x) = List(1) to assign 1 to x for example. The one I wrote is an edge case where the pattern definition does not actually define anything.
Ok so , is out, but perhaps we can find some other syntax that works ? I think I still like || , it does preclude having a user-defined || extractor but I don’t think that’s problematic:
x match {
case A || B || C =>
...
case List(1 || 2, 3, 4) =>
...
}
| in patterns is perfectly fine the way it is. Changing it would be gratuitous.
There are other precedence issues in the language that are much more annoying today, and we can’t fix them because precedence is not to be changed, ever. (For example: x & 1 != 0 doesn’t parse the obvious and useful way.)
“val (A | B) = A: Any” is "val = ". The use case for "val = " is things like “val head :: tail = list”. The use case for “(A | B)” is “x match { case (A | B) => action }”. It would unnecessarily complicate the language to make the patterns allowed for “val”, “for” and “match” distinct – the programmer would then need to know not only the pattern rules, but how they differ in each case. That’s what was meant by “edge case” – it’s a case where reasonable features are used in an unreasonable way. It’s not the sort of thing that can be helped.