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.
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>