scalafunctional-programminganonymous-functionhigher-order-functionscurrying

Currying vs. anonymous function in Scala


I was comparing two ways of defining a higher-order function in Scala:

def f1(elem: Int)(other: Int) = (elem == other)

def f2(elem: Int) = (other: Int) => (elem == other)

The first one uses currying while the second uses an anonymous function.

I am wondering what is the difference, if any, between the two approaches in terms of how Scala implements them and which version is preferable?

Note: Scala now has stopped refering to the first approach as currying in favour of multiple parameter lists. See the linked docs for more details.


Solution

  • The implementations are quite different to the Scala compiler. The curried version compiles down to a Java method by un-currying the parameters:

    def f1(elem: Int, other: Int): Boolean = elem.==(other);
    

    The second version is a method that returns an anonymous function (a Function1), so their signatures are completely different. Though they can often be used interchangeably within Scala code, there is quite a bit more generated code in the second version:

      def f2(elem: Int): Function1 = (new <$anon: Function1>(elem): Function1);
    
      @SerialVersionUID(value = 0) final <synthetic> class anonfun$f2$1 extends scala.runtime.AbstractFunction1$mcZI$sp with Serializable {
        final def apply(other: Int): Boolean = anonfun$f2$1.this.apply$mcZI$sp(other);
        <specialized> def apply$mcZI$sp(other: Int): Boolean = anonfun$f2$1.this.elem$1.==(other);
        final <bridge> <artifact> def apply(v1: Object): Object = scala.Boolean.box(anonfun$f2$1.this.apply(scala.Int.unbox(v1)));
        <synthetic> <paramaccessor> private[this] val elem$1: Int = _;
        def <init>(elem$1: Int): <$anon: Function1> = {
          anonfun$f2$1.this.elem$1 = elem$1;
          anonfun$f2$1.super.<init>();
          ()
        }
      }
    

    I would only consider using the second version in cases where I was explicitly looking to work with Function1 objects. However, I would personally lean towards using the curried version, because you can still get a Function1 back with partial application of the first. The curried version is just as powerful, but won't create Function1 objects when you don't need them.

    scala> f1(1) _
    res1: Int => Boolean = <function1>