Coming back to this… In Scala 3, match
is special since it can also be used in match types. So I believe it should still be a keyword. However, we might change the syntax rules for match so that it behaves like a left-associative infix operator with the same precedence as other alpha-numeric operators. That would make using match more flexible. In particular, we could chain matches:
a match
case P1 => b
case P2 => c
match
case P3 => d
case P4 => e
Another variant would be to also allow match to be used after dot. So match
would behave like a normal method, except that it is a reserved word. That would help with embedding matches in long chains of conditions. Here’s an example, lifted from real code (the exhaustivity checker in our compiler):
def canDecompose(tp: Type): Boolean =
val cls = tp.classSymbol
cls.is(Sealed)
&& cls.isOneOf(AbstractOrTrait)
&& !cls.hasAnonymousChild
&& cls.children.nonEmpty
|| tp.dealias.match
case _: OrType => true
case and: AndType => canDecompose(and.tp1) || canDecompose(and.tp2)
case _ => false
|| tp.isRef(defn.BooleanClass)
|| tp.isRef(defn.UnitClass)
|| cls.isAllOf(JavaEnumTrait)
That’s actually quite readable taking into account how complex a condition it is. Compare with the original that uses old Scala 2 syntax:
def canDecompose(tp: Type): Boolean = {
val dealiasedTp = tp.dealias
(tp.classSymbol.is(Sealed) &&
tp.classSymbol.isOneOf(AbstractOrTrait) &&
!tp.classSymbol.hasAnonymousChild &&
tp.classSymbol.children.nonEmpty ) ||
dealiasedTp.isInstanceOf[OrType] ||
(dealiasedTp.isInstanceOf[AndType] && {
val and = dealiasedTp.asInstanceOf[AndType]
canDecompose(and.tp1) || canDecompose(and.tp2)
}) ||
tp.isRef(defn.BooleanClass) ||
tp.isRef(defn.UnitClass) ||
tp.classSymbol.isAllOf(JavaEnumTrait)
}