1
votes

My understanding about pure functions are that the output of the function only depends on the input. And they are referentially transparent.

But then there are side effects that happens in our code. Below is an example

  import scala.concurrent.Future
  case class Customer(fName: String, lName: String)
  case class Order(orderId: Int, item: String, quantity: Int)
  case class Shipment(shipmentId: Int, orderId: Int, address: String)

  trait CustomerRepo {
    def findCustomer(userId: String): Future[Customer] = ???
    def findLastOrder(customer: Customer): Future[Order] = ???
    def findShipment(orderId: Int): Future[Shipment] = ???
  }

  class ShoppingApp(customerRepo: CustomerRepo) {

    def getLastShipment(userId: String): Future[Shipment] = {
      for {
        customer <- customerRepo.findCustomer(userId)
        lastOrder <- customerRepo.findLastOrder(customer)
        shipment <- customerRepo.findShipment(lastOrder.orderId)
      } yield shipment
    }

  }

Above is a basic example where we do multiple side effects (call to database).

getLastShipment returns a Future. Does that makes is a pure function.

If getLastShipment is not pure then how to make it pure???

1
There is nothing impure about getLastShipment. The only "problem" is that you're using Future, which is eagerly evaluated and breaks RT. Other than that, you're good.Yuval Itzchakov
Futures work against the whole pure thing. Other than this I think to be pure the getLastShipment function should not depend on the context which means that it should explicitly require CustomerRepo as a function parameter.sarveshseri

1 Answers

1
votes

You're pretty close, you're already on the right path using Monads and for-comprehensions, however, Future is fundamentally side-effecting, because it does not suspend its evaluation. (For further information, see my answer here. If you switch your function to use something like cats.effect.IO:

def getLastShipment(userId: String): IO[Shipment] = {
  for {
    customer <- customerRepo.findCustomer(userId)
    lastOrder <- customerRepo.findLastOrder(customer)
    shipment <- customerRepo.findShipment(lastOrder.orderId)
  } yield shipment
}

Then this code is completely pure and referentially transparent.