scalapartialfunctionpartial-functions

Why Scala PartialFunction works without defining isDefinedAt?


It looks First and Second are the same, but why?

First

val iter = List(1, 2, 3, 4, 5).iterator
val first = iter.collect(new PartialFunction[Int, Int]{
  def apply(i: Int) = i
  def isDefinedAt(i: Int) = i > 0 && i < 3
})
first.foreach((println(_)))

Second

val iter2 = List(1, 2, 3, 4, 5).iterator
val second = iter2.collect {
  case i:Int if i > 0 && i < 3 => i
}
second.foreach((println(_)))

Is it because the Scala compiler automatically converts { case i:Int if i > 0 && i < 3 => i } into the implelentation form of First with generating isDefinedAt from if i > 0 && i < 3 part?

Also, case i:Int if i > 0 && i < 3 => i is Case class pattern matching, if I am correct. However, in scala/src/library/scala/PartialFunction.scala, there is no Case class definition for PartialFunction.

trait PartialFunction[-A, +B] extends (A => B)

Then why this case class pattern match works?

I suppose Scala compiler does lots of implicit works intelligently but it confuses me to understand what is happening and how to write Scala code.

If there are good references, instead of language or compiler specifications, to understand Scala code syntax and Scala way of writing code, please suggest.


Solution

  • Is it because the Scala compiler automatically converts { case i:Int if i > 0 && i < 3 => i } into the implelentation form of First with generating isDefinedAt from **if i > 0 && i < 3 ** part?

    Yes, the exact translation is given in Pattern Matching Anonymous Functions. Here it'll be

    new PartialFunction[Int, Int]{
      def apply(x: Int) = x match {
        case i:Int if i > 0 && i < 3 => i
      }
      def isDefinedAt(x: Int) = x match {
        case i:Int if i > 0 && i < 3 => true
        case _ => false
      } 
    }
    

    Note the difference with your first example in apply! You can still call it when isDefined is false.

    Also, case i:Int if i > 0 && i < 3 => i is Case class pattern matching, if I am correct

    If anything, it's the other way around; case classes are called that way because they can be pattern-matched and pattern matching uses case keyword in Scala.