Question

What got me thinking was why the following

<something> match { ... }

could not be rewritten as

<something>.match({ ... })  # error: identifier expected but 'match' found.

I guess it's because it wouldn't have been possible to implement match as a regular method, but I'm not sure. Or perhaps it was for performance reasons.

Also, now that macros are available, would match be possible to be implemented using a macro instead? (not that it should be done, but just hypothetically)

EDIT: This seems related to e.g. What is scala's experimental virtual pattern matcher?; thanks to @om-nom-nom for pointing it out.

Was it helpful?

Solution

By having it as a keyword, it need not be associated to type Any, so the compiler is free to infer the input type of the (partial) function. If it was a method of Any it would take a Function[A, B] as argument.

The practical implications are that

3 match { case "foo" => "bar" }

causes the compile error 'type mismatch'

but a (type paramerterless) matchMethod;

3.matchMethod { case "foo" => "bar" }

causes the runtime exception 'scala.MatchError'

then even if we verbosely explicitly paramerterized the types we still wouldn't get a compile error for the following situation:

"foo".matchMethod[Int, String] { case 3 => "bar" }

rather we would get the runtime exception 'java.lang.ClassCastException' as under the hood we would have to use .asInstanceOf.

The other bonus is syntax highlighting, matchs jump out in code more than yet another method, which I believe it deserves as pattern matching is such a key part of Scala it deserves special attention.

ADDITION: For similar reasons you want try catch to be a keyword construct rather than a function that takes two functions as parameters. match is then consistent with catch, which is also consistent with Java.

This answer is an expansion on Martin Odersky's, which was first pointed out by TravisBrown

OTHER TIPS

samthebest's answer is probably the real reason (I don't know, that's not something I'm familiar with), but there is another way of looking at it that relates to functional programming more generally.

It is well known that matches in functional programming can be done without any special languages features (Church Encoding)

trait List[+T] {
    def mmatch[R](nil: => R, cons: (T, List[T]) => R): R
}
object Nil extends List[Nothing] {
    def mmatch[R](nil: => R, cons: (Nothing, List[Nothing]) => R) = nil
}
class Cons[+T](head: T, tail: List[T]) extends List[T] {
    def mmatch[R](nil: => R, cons: (T, List[T]) => R) = cons(head, tail)
}

def sum(l: List[Int]): Int = l mmatch (
    nil = 0,
    cons = (x, xs) => x + sum(xs)
)

val list = new Cons(1, new Cons(2, Nil))

println(sum(list))

In this interpretation, when you write

sealed trait List[+T]
case object Nil extends List[Nothing]
case class Cons[+T](head: T, tail: List[T]) extends List[T]

the word sealed is the value/term that provides the match function.

So one way of reading your question is, why not just do that? Why not build matches out of other basic language features rather than providing a syntactic match?

The reason is that syntactic match provides some syntactic sugar that people like:

  • Overlapping match functions:

    sealed trait A
    sealed trait B
    case object X extends A
    case object Y extends A with B
    case object Z extends B
    
  • Nested match functions:

    (1 :: 2 :: Nil) match {
        case x :: y :: Nil => ???
    }
    

    This is very awkward to write without syntactic sugar. You can do it; I tried out exploring the possibility when trying to implement monadic extractors; but it sure is less pretty.

  • Automatic selection of open vs closed match functions.

    That is, extractors in Scala are like open match functions because any may fail by returning None; the compiler won't check for a complete match but you can chain as many together as you like and Scala selects the first one. On the other hand, sealed traits provide closed match functions with the benefit of completeness checking. These would need to be provided by separate functions, but Scala lets you use the same match syntax for both.

Personally I have a suspicion that the above requirements do not, ultimately, necessitate special syntactic support for matches. I suspect that other, more general language features can end up providing the same benefit, particularly in the area of nested matches. However, for the time being it simply makes more sense to hit the problem directly with a special match syntax.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top