TL;DR#
Deffunctions are more informative (function signature, function name)Deffunctions are not data, butValfunctions areDeffunctions can be converted toValfunctions by using eta expansion
val function under the hood#
In Scala, a val function is actually a function wrapped within an object
val replicate: (Int, String) => String = (n: Int, text: String) => text * nwill actually be desugared to:
val replicate = new Function2[Int, String, String] { def apply(n: Int, s: String): String = s * n}The magic behind the scene is that each anonymous function is actually an object that extends the FunctionN trait.
// The actual definition is way more complex,// but the rough idea is the sametrait Function1[T, R] { def apply(v1: T): R }trait Function2[T1, T2, R] { def apply(v1: T1, v2: T2): R }trait Function3[T1, T2, T3, R] { def apply(v1: T1, v2: T2, v3: T3): R }Then why we can call replicate(3, "hello") like a normal function? Because Scala compiler will automatically call the apply method for you.
replicate(3, "hello")// is equivalent toreplicate.apply(3, "hello")which makes the code easier to work with.
When def function#
def functions are the most common way to define a function in Scala. They are more informative because:
- The name of the function is contained.
- The name of the function parameters is contained
It’s especially useful when the function signature is complex:
def createDate(year: Int, month: Int, day: Int): Date = ???// createDate: createDate[](val year: Int,val month: Int,val day: Int) => Datethen the function can be called using named parameters:
createDate(day = 1, month = 1, year = 2025)will is much more readable and less ambiguous.
def and val function conversion#
def function can be converted to val function easily by using eta expansion:
def replicate(n: Int, text: String): String = text * n // replicate: replicate[](val n: Int,val s: String) => Stringval replicateVal = replicate _ // replicateVal: (Int, String) => String