Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why was match in Scala implemented as a keyword rather than as a method?

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.

like image 680
Erik Kaplun Avatar asked Oct 27 '13 15:10

Erik Kaplun


People also ask

What does match mean in Scala?

It is a technique for checking a value against a pattern. It is similar to the switch statement of Java and C. Here, “match” keyword is used instead of switch statement. “match” is always defined in Scala's root class to make its availability to the all objects. This can contain a sequence of alternatives.

How do you use match function in Scala?

Using if expressions in case statements First, another example of how to match ranges of numbers: i match { case a if 0 to 9 contains a => println("0-9 range: " + a) case b if 10 to 19 contains b => println("10-19 range: " + b) case c if 20 to 29 contains c => println("20-29 range: " + c) case _ => println("Hmmm...") }

What is one way to implement pattern matching on methods?

Matching on case classes Case classes are especially useful for pattern matching. Notification is a sealed trait which has three concrete Notification types implemented with case classes Email , SMS , and VoiceRecording . Now we can do pattern matching on these case classes: Scala 2.

What is match expression?

A match expression branches on a pattern. The exact form of matching that occurs depends on the pattern. A match expression has a scrutinee expression, which is the value to compare to the patterns. The scrutinee expression and the patterns must have the same type.


2 Answers

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

like image 116
samthebest Avatar answered Sep 17 '22 11:09

samthebest


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.

like image 44
Owen Avatar answered Sep 20 '22 11:09

Owen