简体   繁体   中英

What's the reasoning behind adding the “case” keyword to Scala?

Apart from:

case class A

... case which is quite useful?

Why do we need to use case in match ? Wouldn't:

x match {
  y if y > 0 => y * 2
  _ => -1
}

... be much prettier and concise?

Or why do we need to use case when a function takes a tuple? Say, we have:

val z = List((1, -1), (2, -2), (3, -3)).zipWithIndex

Now, isn't:

z map { case ((a, b), i) => a + b + i }

... way uglier than just:

z map (((a, b), i) => a + b + i)

...?

First, as we know, it is possible to put several statements for the same case scenario without needing some separation notation, just a line jump, like :

x match {
       case y if y > 0 => y * 2
                          println("test")
                          println("test2")  // these 3 statements belong to the same "case"
}

If case was not needed, compiler would have to find a way to know when a line is concerned by the next case scenario.

For example:

x match {
   y if y > 0 => y * 2
   _ => -1
}

How compiler would know whether _ => -1 belongs to the first case scenario or represents the next case?

Moreover, how compiler would know that the => sign doesn't represent a literal function but the actual code for the current case ?

Compiler would certainly need a kind of code like this allowing cases isolation: (using curly braces, or anything else)

x match {
    {y if y > 0 => y * 2}
    {_ => -1}  // confusing with literal function notation
}

And surely, solution (provided currently by scala) using case keyword is a lot more readable and understandable than putting some way of separation like curly braces in my example.

Adding to @Mik378's answer:

When you write this: (a, b) => something , you are defining an anonymous Function2 - a function that takes two parameters.

When you write this: case (a, b) => something , you are defining an anonymous PartialFunction that takes one parameter and matches it against a pair.

So you need the case keyword to differentiate between these two.

The second issue, anonymous functions that avoid the case , is a matter of debate:

https://groups.google.com/d/msg/scala-debate/Q0CTZNOekWk/z1eg3dTkCXoJ

Also: http://www.scala-lang.org/old/node/1260

For the first issue, the choice is whether you allow a block or an expression on the RHS of the arrow.

In practice, I find that shorter case bodies are usually preferable, so I can certainly imagine your alternative syntax resulting in crisper code.

Consider one-line methods. You write:

def f(x: Int) = 2 * x

then you need to add a statement. I don't know if the IDE is able to auto-add parens.

def f(x: Int) = { val res = 2*x ; res }

That seems no worse than requiring the same syntax for case bodies.

To review, a case clause is case Pattern Guard => body .

Currently, body is a block, or a sequence of statements and a result expression.

If body were an expression, you'd need braces for multiple statements, like a function.

I don't think => results in ambiguities since function literals don't qualify as patterns, unlike literals like 1 or "foo" .

One snag might be: { case foo => ??? } { case foo => ??? } is a "pattern matching anonymous function" (SLS 8.5). Obviously, if the case is optional or eliminated, then { foo => ??? } { foo => ??? } is ambiguous. You'd have to distinguish case clauses for anon funs (where case is required) and case clauses in a match .

One counter-argument for the current syntax is that, in an intuition deriving from C, you always secretly hope that your match will compile to a switch table. In that metaphor, the cases are labels to jump to, and a label is just the address of a sequence of statements.

The alternative syntax might encourage a more inlined approach:

x match {
  C => c(x)
  D => d(x)
  _ => ???
}
@inline def c(x: X) = ???
//etc

In this form, it looks more like a dispatch table, and the match body recalls the Map syntax, Map(a -> 1, b -> 2) , that is, a tidy simplification of the association.

One of the key aspects of code readability is the words that grab your attention. For example, return grabs your attention when you see it because you know that it is such a decisive action (breaking out of the function and possible sending a value back to the caller).

Another example is break --not that I like break , but it gets your attention.

I would agree with @Mik378 that case in Scala is more readable than the alternatives. Besides the compiler confusion he mentions, it gets your attention.

I am all for concise code, but there is a line between concise and illegible. I will gladly make the trade of 4n characters (where n is the number of cases) for the substantial readability that I get in return.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM