TL;DR#
Def
functions are more informative (function signature, function name)Def
functions are not data, butVal
functions areDef
functions can be converted toVal
functions 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 * n
will 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) => Date
then 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