What's difference for function value and anonymous function?

For instance, I wrote code below:

scala> val status: Int=>String = { case 200 => “ok”; case 500 => “error”; case other => “unknown” }
status: Int => String =

scala> val status2 = (x:Int) => { if (x==200) “ok” else if (x==500) “error” else “unknown” }
status2: Int => String =

Both have the same effect by calling.
Can you tell me their difference? thanks a lot.

From your point of view, there is no difference. They are both values defined by using “function literals”. The REPL shows you that they are both “Lambda…” which stands for function literal:

 ➜ scala
Welcome to Scala 3.1.0 (11.0.13, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

scala> val status: Int => String = { case 200 => "ok"; case 500 => "error"; case other => "unknown" }
val status: Int => String = Lambda$1362/0x00000008406bc840@299a43d9

scala> val status2: Int => String = x => if x == 200 then "ok" else if x == 500 then "error" else "unknown"
val status2: Int => String = Lambda$1384/0x00000008406f1840@1be3f8f8

You are simply using pattern matching (plus the partial function syntax) in the first one (then making it a complete function by having a final case that matches every pattern), and if/else in the second one. The only difference is a matter of choice/taste between pattern matching versus if/else. It’s not related to anonymous functions. You could write these same functions with def too:

scala> def stat(x: Int): String = x match
     |   case 200 => "ok"
     |   case 500 => "error"
     |   case other => "unknown"
def stat(x: Int): String

scala> def stat2(x: Int): String =
     |   if x == 200 then "ok"
     |   else if x == 500 then "error"
     |   else "unknown"
def stat2(x: Int): String

So far, no difference. Just if/else versus pattern matching. Doesn’t matter if it’s an anonymous function or not.

Some info on Partial Functions
I think your confusion might be coming from the Partial Function Syntax (which lets you skip x match):

{ case 200 => "ok"; ... }

Technically, if you didn’t have the LAST case case other => ... that matches every other input, then there would be a difference. Unlike if/else this syntax allows you to leave the “final else part” undefined. Let’s try it:

scala> val status: Int => String = { case 200 => "ok"; case 500 => "error" }
val status: Int => String = Lambda$1406/0x00000008406fd040@3dded90a

scala> status(123)
scala.MatchError: 123 (of class java.lang.Integer)
  at repl$.rs$line$5$.$init$$$anonfun$1(rs$line$5:1)
  at repl$.rs$line$5$.$init$$$anonfun$adapted$1(rs$line$5:1)
  ... 30 elided

Let’s take a look at the book “Programming in Scala” 5th Edition by Odersky, Venner, Spoon, Sommers. On Page 292-293 (I modified a bit):

One other generalization is worth noting: a sequence of cases gives you a
partial function.

scala> val second: List[Int] => Int = { case x :: y :: _ => y }
-- Warning:
1 |val second: List[Int] => Int = { case x :: y :: _ => y }
  |                                 ^
  |                                 match may not be exhaustive.
  |                                 It would fail on pattern case: List(_), Nil
val second: List[Int] => Int = Lambda$1594/0x000000084079b840@7ac90dab

The typical example of a partial function is a pattern matching function lit-
eral like the one in the previous example. In fact, such an expression gets
translated by the Scala compiler to a partial function by translating the pat-
terns twice—once for the implementation of the real function, and once to
test whether the function is defined or not.
For instance, the function literal { case x :: y :: _ => y } gets translated
to the following partial function value:

new PartialFunction[List[Int], Int]:
  def apply(xs: List[Int]) =
    xs match
      case x :: y :: _ => y
  def isDefinedAt(xs: List[Int]) =
    xs match
      case x :: y :: _ => true
      case _ => false
1 Like

You are a bit confused in terminology, both status & status2 are function values.
In the same sense both: { case 200 => “ok”; case 500 => “error”; case other => “unknown” } & (x:Int) => { if (x==200) “ok” else if (x==500) “error” else “unknown” }
The former is just the default syntax most people use when teaching the concept of lambdas, whereas the first one is just an alternate syntax which is useful for when you want / need to pattern match the inputs of the lambda.

Note that the first one is just sugar syntax for:

val status: Int => String = (x: Int) => x match {
  case 200 => “ok”
  case 500 => “error”
  case _ => “unknown”

So no, there are basically the “same thing”, just different syntax.

Also, as @spamegg1 explained, depending on the context the pattern match syntax will create a PartialFunction instead of a total Function1, it will do that only when that is the expected type; the common example would be collect

Thank you above two. I have got the ideas. :slight_smile:

1 Like

The details are not quite right in the previous answers, although I agree it shouldn’t matter to you.

A “pattern-matching anonymous function”, the block of cases, is translated to either a PF or a function depending on context. The interesting part is that it gets an applyOrElse method. That is much better than the naive apply as shown.

I do remember that it is taught as isDefinedAt / apply. I contributed a doc tweak as a corrective.

The other point is that function literal syntax is also translated to PF or function depending on expected type. (Per an enhancement at some point.) I guess it’s recent enough to merit a mention:

➜  scala
Welcome to Scala 2.13.7 (OpenJDK 64-Bit Server VM, Java 17.0.1).
Type in expressions for evaluation. Or try :help.

scala> (1 to 5).collect(_ < 3)
val res0: IndexedSeq[Boolean] = Vector(true, true, false, false, false)

➜  sdk use scala 2.12.15

Using scala version 2.12.15 in this shell.
➜  scala
Welcome to Scala 2.12.15 (OpenJDK 64-Bit Server VM, Java 17.0.1).
Type in expressions for evaluation. Or try :help.

scala> (1 to 5).collect(_ < 3)
<console>:12: error: type mismatch;
 found   : Int => Boolean
 required: PartialFunction[Int,?]
       (1 to 5).collect(_ < 3)
1 Like