Higher Order Functions and Closures in Scala

scala
Reading Time: 2 minutes

In this blog, we will go through the concepts of higher order functions and closures in Scala with the help of example.

1. Higher Order Functions

A higher order function takes other functions as parameter or returns a function as a result. Let us understand it better with the help of examples:

a) When a method is passed as an argument:



import java.time.LocalTime

object MarketStatus {
  val OPEN  = "Open"
  val CLOSE = "Close"
}

object HigherOrderFunctionEx1 extends App {

  import MarketStatus._

  def isMarketOpen(timeAsStr: String): Boolean = {
    val time: LocalTime = LocalTime.parse(timeAsStr)
    time.isAfter(LocalTime.parse("05:00:00")) && time.isBefore(LocalTime.parse("20:00:00"))
  }

  def displayMarketStatus(f: String => Boolean, transactionTime: String): String = {
    if (f(transactionTime)) {
      OPEN
    } else {
      CLOSE
    }
  }

  val marketStatus = displayMarketStatus(isMarketOpen, "13:00:00")
  
  println(marketStatus)
}

Output: Open

In the above code, isMarketOpen checks if the time at which the transaction is made is after 5 a.m. and before 8 p.m. If it is so, then that indicates that the market is open. This function is passed as an argument to the method displayMarketStatus.

The criteria of market open or close can change overtime. So, all we have to do is while calling the method displayMarketStatus, pass the function which contains the latest criteria of checking the market status.


b) When a function returns a method:


import java.time.LocalTime

object MarketStatus {
  val OPEN  = "Open"
  val CLOSE = "Close"
}

object HigherOrderFunctionEx2 extends App {

  import MarketStatus._

  def isMarketOpen(timeAsStr: String, companyName: String): (String) => String = {
    val time: LocalTime = LocalTime.parse(timeAsStr)

    val status = if (time.isAfter(LocalTime.parse("05:00:00"))
                     && time.isBefore(LocalTime.parse("20:00:00"))) {
      OPEN
    } else {
      CLOSE
    }

    productName: String => s"Market is $status for product : $productName and company: $companyName"
  }

  def getMarketStatus: String => String = isMarketOpen("12:00:00", "Company ABC")

  val marketStatus: String = getMarketStatus("Iron")

  println(marketStatus)
}

Output:
Market is Open for product : Iron and company: Company ABC

In the above program, getMarketStatus returns a function which takes the name of the product and results into a statement stating the market status of the product and company passed.

2. Closures:

Closure is a “first-class function” whose return value depends on the value of one or more “free variable” defined outside this function. It can be either a named or anonymous function.

This will help when we need to pass a scala function around like a variable and the function can refer to some fields that are in the same scope as the function when declared.


class Market {
  def marketStatusForProduct(f: String => Unit, productName: String) {
    f(productName)
  }
}

object ClosureExample extends App {
  def displayMarketStatus(productName: String): Unit = {
    println(s"Market is $status for product: $productName")
  }

  val market = new Market

  var status = "Open"
  market.marketStatusForProduct(displayMarketStatus, "Iron ore")

  status = "Close"
  market.marketStatusForProduct(displayMarketStatus, "Gold")
}

Output:
Market is Open for product: Iron ore
Market is Close for product: Gold

We can derive the following observations from the above code:

  • displayMarketStatus method references the variable status from marketStatusForProduct method of the Market class.
  • In the second call to marketStatusForProduct method, the value of status is updated inside the method. Thus when the closure is executed, it took the most recent state of the free variable (state).

References:

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading