scalapartialfunctionpartial-functions

Why using a variable makes a partial function less partial?


I do not understand why using a variable for a temporary value makes the partial function different:

val f1: PartialFunction[Option[Int], Int] = { b =>
  val i = identity(b)
  i match {
    case Some(res) => res
  }
}
val f2: PartialFunction[Option[Int], Int] = { b =>
  identity(b) match {
    case Some(res) => res
  }
}

f1.isDefinedAt(None)
f2.isDefinedAt(None)

The result is true / false with Scala 2.13.12 and Scala 3.3.1. The first version shows match exhaustivity warning, the second one does not. The code does not compile with Scala 2.12.18, error is in the first version:

type mismatch;

found : Option[Int] => Int

required: PartialFunction[Option[Int],Int]

How is the second version more "partial" than the first one?


Solution

  • I think the language specification answers this:

    https://www.scala-lang.org/files/archive/spec/3.4/06-expressions.html

    When a PartialFunction is required, an additional member isDefinedAt is synthesized, which simply returns true. However, if the function literal has the shape x => x match { $...$ }, then isDefinedAt is derived from the pattern match in the following way: each case from the match expression evaluates to true, and if there is no default case, a default case is added that evaluates to false.

    The first versions does not have the expected shape for a special case conversion of a Single Abstact Method to a partial function, therefore a normal (total) function is created which is later converted to a partial function.

    Maybe requiring partial functions to be written as a Pattern Matching Anonymous Function would be less confusing, but I guess there is some reason or history behind this.