Search code examples
scalaanonymous-functionpartialfunction

What is the difference between anonymous functions and partial functions?


I was reading about scala anonymous functions here and saw that they can take the format:

{ case p1 => b1 … case pn => bn }

However, I thought that this was how partial functions were written. In fact, in this blog post, the author calls a partial function an anonymous function. At first he says that collect takes a partial function but then appears to call it an anonymous function ("collect can handle the fact that your anonymous function...").

Is it just that some anonymous functions are partial functions? If so, are all partial functions anonymous? Or are they only anonymous if in format like Alvin Alexander's example here:

val divide2: PartialFunction[Int, Int] = {
    case d: Int if d != 0 => 42 / d
}

Solution

  • From the documentation on pattern matching anonymous functions that you linked:

    If the expected type is SAM-convertible to scala.Functionk[S1,…,Sk, R], the expression is taken to be equivalent to the anonymous function:

    (x1:S1,…,xk:Sk) => (x1,…,xk) match {   
        case p1 => b1 … case pn => bn 
    }
    

    Here, each xi is a fresh name. As was shown here, this anonymous function is in turn equivalent to the following instance creation expression, where T is the weak least upper bound of the types of all bi.

    new scala.Functionk[S1,…,Sk, T] {   
      def apply(x1:S1,…,xk:Sk): T = (x1,…,xk) match {
        case p1 => b1 … 
        case pn => bn   
      } 
    } 
    

    If the expected type is scala.PartialFunction[S, R], the expression is taken to be equivalent to the following instance creation expression:

    new scala.PartialFunction[S, T] {   
      def apply(x: S): T = x match {
        case p1 => b1 … case pn => bn   
      }   
      def isDefinedAt(x: S): Boolean = {
        case p1 => true … case pn => true
        case _ => false   
      } 
    }
    

    Your first code snippet is a pattern matching anonymous function, but not necessarily a partial function. It would only be turned into a PartialFunction if it was given to a method with a PartialFunction parameter or assigned to a variable of type PartialFunction.

    So you are right that just some (pattern matching) anonymous functions are partial functions (AFAIK, function literals defined with fat arrows, such as x => x, can only ever be used to create FunctionN instances and not PartialFunction instances).

    However, not all partial functions are anonymous functions. A sugar-free way to define PartialFunctions is extending the PartialFunction trait (which extends Function1) and manually overriding the isDefinedAt and apply methods. For example, divide2 could also be defined like this, with an anonymous class:

    val divide2 = new PartialFunction[Int, Int] {
      override def isDefinedAt(x: Int) = x != 0
      override def apply(x: Int) = 42 / x
    }
    

    You probably won't see this very often, though, as it's a lot easier to just use pattern matching to define a PartialFunction.


    In the blog post by Alvin Alexander you linked, the author refers to the pattern matching anonymous partial function literal as an anonymous function only because it happens to be both a partial function and an anonymous function. You could also define the function like so:

    
    List(42, "cat").collect(new PartialFunction[Any, Int] {
      def isDefinedAt(x: Any) = x.isInstanceOf[Int]
      def apply(x: Any) = x match {
        case i: Int => i + 1
      }
    })
    

    It's no longer an anonymous function, although it's still an anonymous object that's the instance of an anonymous class. Or you could define a singleton object beforehand and then use that.

    object Foo extends PartialFunction[Any, Int] {
      def isDefinedAt(x: Any) = x.isInstanceOf[Int]
      def apply(x: Any) = x match {
        case i: Int => i + 1
      }
    }
    List(42, "cat").collect(Foo)
    

    No matter how you define it, though, it's a partial function.