Ty Scales

A Practical Use Case for Higher Order Functions

Have you ever encountered this scenario before?

Lets say you have a class User.

case class User(firstName: String, lastName: String, address: String)

You’re using this class in production to store information retrieved from an endpoint. Now imagine you are given a new task where you need to fetch a User from a new endpoint. However, This endpoint does not contain the address field, you’ll have to get that field from a second new endpoint. What do you do?

One solution could be to create 2 new classes and a function that combines them in to a user.

case class UserWithoutAddress(firstName: String, lastName: String)
case class UserAddress(address: String)

def makeUser(partialUser: UserWithoutAddress, address: UserAddress): User = 
    User(partialUser.firstName, partialUser.lastName, address.address)

What if instead of 3 fields in your User class, you have 20?

With a higher order function, these extra classes can be avoided all together. Instead of a returning a UserWithoutAddress, we can return a function String => User that will complete the User for us once we obtain the address at a later time.

def getUserWithoutAddress(): String => User = {
    User("foo", "bar", _)
}

val partialUser: String => User = getUserWithoutAddress()
val user: User = partialUser("123 main st")

If you use Circe, you can even define your json decoders as such:

implicit val partialUser: Decoder[String => User] = {
    (c: Hcursor) => 
        for {
            firstName <- c.downField("firstName").as[String]
            lastName <- c.downField("lastName").as[String]
        } yield User(firstName, lastName, _)
}

#Functional-Programming