Scala | Functions

Reading Time: 5 minutes

A function is a collection of expressions that perform a certain task. We can divide a code in scala into separate functions, where each function must perform a specific task. We use functions to put some common and repetitive tasks into a single function, so instead of writing the same code again and again for different inputs, we can simply call the function. A function is a complete object that we can store in a variable. It makes it easier to debug and modify the code. Scala functions are first-class values because Scala is rich with built-in functions, and it also lets us create our own.

//Function Example
def exampleFunction(firstParameter: Int, secondParameter: Int): Int = {
  val temp = 2 + 3
  temp
}

Below declared is how we write syntax for a function in the form of an Example:

Scala Function Declaration Example
Function in Scala on IntelliJ IDEA

How to use Function in Scala

A function performs single or multiple tasks. To use any function, we need to call it. Scala provides us with different ways to call a function, i.e. we can call them directly or by using the class instance.

As we saw in the above example. Let’s see an example for the Class Instance call for function.

Scala Function Class Instance
Class Instance Function Call

Now Let’s talk about how we call those functions:

Types of Function Call

Call By Value:

Function arguments are Call By Value by default. In the by value call,we compute the exact value of the expression before the function evaluates itself and after that the same value is used throughout the function definition.

Call By Name:

In Call By Name we use this => symbol to Indicate that the function calls by name, and every call to the parameter evaluates the argument each time it is called.

Code Snippet for Call By Value and Call By Name:

Let’s see what happens in the code above:

When the CallByValue function is called we can see the output for the function is the same in each call but in the case of CallByName, the Output is different since the function evaluates the arguments every time It is used.

While these two are the ways to call functions, the functions can be with parameters or without parameters.

//With Parameter
def WithParameter(Parameter: Int): Int = {
  val temporaryVariable = 2 * 3
  temporaryVariable
}
//Without Parameter
def WithoutParameter: Int = {
  val temporaryVariable = 2 * 3
  temporaryVariable

Types Of Function in Scala:

Below are the different types of functions in Scala:

Currying Function:

In Scala, Currying is a way to transform a function that accepts multiple arguments into a chain of functions with a single argument.

//Currying Function with a single argument

object CurryingFunction
{
    
    def addNumber(firstParameter: Int)(secondParameter: Int) => firstParameter + secondParameter;
    def main(args: Array[String])
    {
        println(addNumber(20)(19));
    }
}

Anonymous Function:

An Anonymous Function is a type of function which does not contain a name. It is a lightweight function that is useful when we want to create a function in one line of code. Also, Anonymous functions are functioning literals, and at runtime, they instantiate into objects called function values.

//Anonymous Function with Parameter.

object AnonymousFunction {

  def main(args: Array[String]) {

    val firstFunctionWithParameter = (FirstNumber:Int, SecondNumber:Int) => FirstNumber + SecondNumber
    val secondFunctionWithParameter = (_:Int) + (_:Int)
    println(firstFunctionWithparameter(8,6))
    println(secondFunctionWithParameter(5,10))
  }

In the first syntax above, => is a transformer. The transformer is used to convert the parameter list to the left of the symbol into a new result using the expression on the right.

In the above second syntax, _ (underscore) character is a wildcard is a shorthand way to represent a parameter who appears only once in the anonymous function.

Nested Function:

In Scala, we can define a Scala function inside another function. It is mainly used in tail recursion and It is also used to avoid the use of loops.

//Nested Function

object NestedFunction {
  def maxAndMin(a: Int, b: Int) = {
    def maxValue() = {
      if(a > b) {
      println("Max is: " + a)
      }
      else {
      println("Max is: " + b)
      }
    }
    def minValue() = {
      if (a < b) {
      println("Min is: " + a)
      }
      else {
      println("Min is: " + b)
      }
     }
     maxValue();
     minValue();
  }
maxAndMin(5, 6)
}

Closure Function:

Scala Closure functions use one or more free variables where we declare the free variable outside of the Closure Function and not include It as a parameter of this function and the return value of this function is dependent on these free variables.

//Closure Function

object ClosureFunction {
  def main(args: Array[String])
  {
    println( "Final_Sum(1) value = " + sum(1))
    println( "Final_Sum(2) value = " + sum(2))
    println( "Final_Sum(3) value = " + sum(3))
  }
 var a = 4
 val sum = (b:Int) => b + a
}

Recursive Function:

Recursion is quite common in functional programming as It involves breaking a problem into smaller pieces. Finding the solution for the smallest piece and integrate It back into the last call. To achieve this, the recursive function will call Itself again and again until a predefined case to stop is met. Recursion makes this possible by storing the value in what is called Stackframe.

//Recursive Function

object Factorial
{
    def fact(n:Int): Int=
    {
        if(n <= 1) 1
        else n * fact(n - 1)
    }
      
    def main(args:Array[String])
    {
        println(fact(10))
    }
}

In the above code block if the Input number is higher then their arrises the Issue of Stack Overflow.

Tail Recursion:

A recursive function is tail-recursive if the recursive call is the last thing that the function does. The tail-recursive functions are better than recursive functions as the compiler can optimize tail-recursion. Tail Recursion does not keep record of the previous state and this is how It avoids the problem of StackOverflow.

//Tail Recusion
import scala.annotation.tailrec
  
object tailRecursion
{
    def factorial(n: Int): Int =
    {
      @tailrec 
      def factorialAcc(acc: Int, n: Int): Int =
      {
         if (n <= 1)
         acc
         else 
         factorialAcc(n * acc, n - 1)
      }
    factorialAcc(1, n)
    }
      
    def main(args:Array[String])
    {
      println(factorial(5))
    }
}

Conclusion:

Scala has different types and ways to declare functions.It is also highly dependent on functions since It avoids mutability and use of loops in It’s programs but when we need to iterate in programs, functions in Scala helps in accomplishing that.

References:

https://data-flair.training/blogs/scala-function/

https://www.baeldung.com/scala/functions-methods

https://www.baeldung.com/scala/parameters-by-value-by-name

knoldus