Kotlin: An Illustrated Guide • Chapter 7

# Lambdas and Function References As we’ve seen, functions are a basic building block of Kotlin code. Throughout this series, we’ve written a lot of them, all using the `fun` keyword. Kotlin also gives us another way to write functions - lambdas!

To help us learn about function types, function references, and lambdas, we’ll need to pay a visit to Bert’s Snips & Clips.

## Bert’s Snips & Clips

Bert’s Snips & Clips is the salon to go for a clean haircut and a nice smooth shave. Although he prides himself on his low prices, sometimes he offers coupons that give the customer \$5 off, to lower the price even further. Once the customer has their fresh new haircut, he needs to calculate the total cost, so that he can charge the customer the right amount. Bert’s pretty good at math, but to make this fast and easy, he created a simple Kotlin function to calculate the total.

His function needed to account for tax and the five-dollars coupon. Here’s what he wrote:

``````// Tax is 9%, so we'll multiply by 109% to get the total with tax included.
val taxMultiplier = 1.09

fun calculateTotalWithFiveDollarDiscount(initialPrice: Double): Double {
val priceAfterDiscount = initialPrice - 5.0
val total = priceAfterDiscount * taxMultiplier

}``````

If the customer has a \$20 haircut and presents a \$5 off coupon, he simply runs the function like this:

``````fun main() {
val total = calculateTotalWithFiveDollarDiscount(20.0)
println("\$%.2f".format(total))
}``````

When he runs this code, it prints `\$16.35`.

One day, one of Bert’s customers spent a lot of money on haircuts for the whole family, and she was disappointed that they only had a single coupon for five dollars off. In order to reward his most loyal, high-paying customers, he decided to introduce a 10% off coupon. That way, the more money they spend at his salon, the more dollars would be discounted. Alongside the original function, Bert created a second function, which accommodates the new percent-based coupon. To calculate the price after a 10% discount, he just multiplies the initial price by 90%.

``````fun calculateTotalWithFiveDollarDiscount(initialPrice: Double): Double {
val priceAfterDiscount = initialPrice - 5.0
val total = priceAfterDiscount * taxMultiplier

}

fun calculateTotalWithTenPercentDiscount(initialPrice: Double): Double {
val priceAfterDiscount = initialPrice * 0.9
val total = priceAfterDiscount * taxMultiplier

}``````

When he looked at these functions, he realized that they’re almost exactly the same, except for one small part - the part that calculates the discounted price.

If only he could find a way to pass code as an argument… then he could consolidate his two functions down to one function that would look something like this:

``````fun calculateTotal(
initialPrice: Double,
applyDiscount: ???
): Double {
val priceAfterDiscount = applyDiscount(initialPrice)
val total = priceAfterDiscount * taxMultiplier

}``````

In other words, he just wants to tell `calculateTotal()` to apply a discount in a different way each time he calls it. If he could pass a function as an argument to `calculateTotal()`, that would solve his problem. But passing a function as an argument to another function? How could that be possible?

With Kotlin’s function types, it’s easy!

## Introduction to Function Types

We saw way back in Chapter 1 how we could create variables that hold values. For example, to create a simple String variable that holds text, we can do this:

Similarly, parameters are variables in a function where the calling code passes in their values when invoking the function. For example:

So far, every time that we’ve assigned a variable or passed an argument to a function, we’ve been dealing with values of simple types like `String`, `Int`, and even more complex objects of our own types, like `Circle`.

In addition to assigning simple values like these, Kotlin also lets you assign functions.

To demonstrate this, here’s a simple function to calculate a flat dollar discount, like a \$5-off coupon:

``fun discountFiveDollars(price: Double): Double = price - 5.0``

As you already know, you can call this function, like so:

``val discountedPrice = discountFiveDollars(20.0) // Result is 15.0``

In addition to calling this function, we can also assign it to a variable like this.

``val applyDiscount = ::discountFiveDollars``

Notice the difference between these two lines of code. In Listing 7.6, we’re assigning the result of a function call, but in Listing 7.7, we’re assigning the function itself.

In the code above, `::discountFiveDollars` is a function reference. We call it that because it refers to a function. By assigning this function to a variable, it’s kind of like giving `discountFiveDollars()` another name. Now we can call `applyDiscount()` the same way that we called `discountFiveDollars()`, and it does the same thing.1

``val discountedPrice = applyDiscount(20.0) // Result is 15.0``

Whether we call `discountFiveDollars()` in Listing 7.6 above, or call `applyDiscount()` here, the result is the same: `15.0` (that is, \$15.00).

As you might recall, every time that we declare a variable, that variable has a type, even if it’s not explicitly written out in the code. For example:

``````val name = "Bert"    // name's type is String
val hasCoupon = true // hasCoupon's type is Boolean
val price = 12.50    // price's type is Double``````

So then, you might be wondering about the type of the `applyDiscount` variable.

When a variable holds a function, its type is a combination of all of its parameter types and its return type. In the case of the `discountFiveDollars()` function, these include a single parameter of type `Double` and a return type of `Double`.

A function’s type can be assembled by:

1. Keeping its parentheses
2. Keeping its types
3. Converting the colon `:` to an arrow `->`.

Let’s do that with `discountFiveDollars()`.

So, the type of `discountFiveDollars()` is `(Double) -> Double`. Knowing this, you can now write the type of `applyDiscount` explicitly:

``val applyDiscount: (Double) -> Double = ::discountDollars``

All of the types that we’ve seen up until now have had no spaces in them, like `String`, `Int`, and `Double`. As you can see, function types like `(Double) -> Double` are a bit long, but they’re easy to figure out! The parameter types go inside the parentheses, and the result type goes to the right of the arrow.

For functions that have multiple parameters, separate the parameter types with a comma. For example, here’s a function that has two parameters - a `String` and a `Double` - and it returns a `Double`. When assigning this function to a variable, that variable’s type will be `(String, Double) -> String`.

``````fun menuItemDescription(name: String, price: Double): String =
"A \$name costs \$price before discounts and tax."

### Two functions of the same type

As you might recall, if you have two values of the same type, such as two `String` values, then you can assign (and reassign) those two `String` values to the same variable.

``````var couponCode = "FIVE_BUCKS"
couponCode = "TAKE_10"``````

Similarly, if you have two functions of the same type - that is, functions that have the same parameter types and return type - then you can assign (and reassign) those two functions to the same variable.

To demonstrate this, let’s introduce a function to calculate the discount for a 10%-off coupon. Since it has the same parameter and result types as `discountFiveDollars()`, we can assign either of these functions to the same variable.

``````fun discountFiveDollars(price: Double): Double = price - 5.0
fun discountTenPercent(price: Double): Double = price * 0.9

var applyDiscount = ::discountFiveDollars
applyDiscount = ::discountTenPercent``````

Note that the parameter names do not have to match. Just the types have to match. This code works just the same as the code above:

``````fun discountFiveDollars(initialPrice: Double): Double = initialPrice - 5.0
fun discountTenPercent(originalPrice: Double): Double = originalPrice * 0.9

var applyDiscount = ::discountFiveDollars
applyDiscount = ::discountTenPercent``````

For functions that have multiple parameters, keep in mind that the parameters must match in the same order.

For example, here are two functions. Both return a String. Both accept two parameters - one `String` and one `Double`. However, since the order of those parameters doesn’t match, the types of those functions don’t match, so you can’t assign them to the same variable, or else you get an error:

``````fun menuItemDescription(name: String, price: Double): String =
"A \$name costs \$price before discounts and tax."

fun sillyMenuItemDescription(price: Double, name: String): String =
"You want a \$name? It's gonna run you \$price, not counting coupons, tax, and whatnot!"

Well, we’ve successfully assigned a function to a variable. That can be helpful, but things get even more interesting when we assign a function to a parameter. In other words, we can pass a function as an argument to a function! This is exactly what Bert needed way back in Listing 7.4.

### Passing Functions to Functions

Now that we know what function types are, let’s update Bert’s `calculateTotal()` function. We’ll take Listing 7.4 above and make just a few small changes to it so that it accepts a parameter called `applyDiscount` that has a function type of `(Double) -> Double`.

``````fun calculateTotal(
initialPrice: Double,
applyDiscount: (Double) -> Double
): Double {
// Apply coupon discount
val priceAfterDiscount = applyDiscount(initialPrice)
// Apply tax
val total = priceAfterDiscount * taxMultiplier

}``````

With this code in place, Bert can call `calculateTotal()` with a function reference! Let’s define a few more functions that match the type `(Double) -> Double`, and then call `calculateTotal()` with each of them:

``````fun discountFiveDollars(price: Double): Double = price - 5.0
fun discountTenPercent(price: Double): Double = price * 0.9
fun noDiscount(price: Double): Double = price

val withFiveDollarsOff = calculateTotal(20.0, ::discountFiveDollars) // \$16.35
val withTenPercentOff  = calculateTotal(20.0, ::discountTenPercent)  // \$19.62
val fullPrice          = calculateTotal(20.0, ::noDiscount)          // \$21.80``````

Yay! Bert is now able to calculate the total for different types of coupons, without needing to create multiple versions of `calculateTotal()` for each one!

In addition to sending a function into another function, you can also return a function from a function! Let’s look at that next!

### Returning Functions from Functions

Instead of typing in the name of the function each time he calls `calculateTotal()`, Bert would like to just enter the coupon code from the bottom of the coupon that he receives from the customer. To do this, he just needs a function that accepts the coupon code and returns the right discount function. In other words, it’ll have one parameter that’s a `String`, and its return type will be `(Double) -> Double`.

A when expression makes this function easy!

``````fun discountForCouponCode(couponCode: String): (Double) -> Double = when (couponCode) {
"FIVE_BUCKS" -> ::discountFiveDollars
"TAKE_10"    -> ::discountTenPercent
else         -> ::noDiscount
}``````

And, of course, we can update Listing 7.17 to use the new `discountForCouponCode()` function.

``````val withFiveDollarsOff = calculateTotal(20.0, discountForCouponCode("FIVE_BUCKS")) // \$16.35
val withTenPercentOff  = calculateTotal(20.0, discountForCouponCode("TAKE_10"))    // \$19.62
val fullPrice          = calculateTotal(20.0, discountForCouponCode("NONE"))       // \$21.80``````

Functions like `calculateTotal()` and `discountForCouponCode()` above, which accept functions as arguments and/or return them as results, are called higher-order functions.

So far, we’ve been able to achieve a lot with function references! They can be quite helpful when you’ve already written the function that you want to reference. But Kotlin also gives us another, more concise way to assign functions to variables and parameters - lambdas!

## Introduction to Lambdas

As you might recall from Chapter 1, a literal is when you directly write out a value in your code. For example, in Kotlin, you can create literals for basic types such as `String`, `Int`, and `Boolean`. The highlighted parts of the code below are values that are written as literals.

``````val string: String = "This is a string"
val integer: Int = 49
val boolean: Boolean = true``````

Just as you can write literals of Strings, Ints, and Booleans, you can also write a literal of a function!

“Wait,” I can hear you say, “we’ve already been writing functions! How is this any different?” Yes, we’ve been writing named functions with the `fun` keyword, but we’ve never defined a function directly in an expression, such as on the right-hand side of an assignment, or directly inside a function call.

Let’s take another look at the `discountFiveDollars()` function from earlier in this chapter. We defined that function and then assigned it to a variable by using a function reference. Here’s what it looked like:

``````fun discountFiveDollars(price: Double) = price - 5.0
val applyDiscount: (Double) -> Double = ::discountFiveDollars``````

Instead of defining the `discountFiveDollars()` function with the `fun` keyword, we can rewrite it as a function literal like this:

``val applyDiscount: (Double) -> Double = { price: Double -> price - 5.0 }``

The highlighted part of the code above is a function literal. In Kotlin, a function literal written like this is called a lambda. Lambdas are functions, just like the ones we’ve written so far. They’re simply expressed differently. To write a lambda, use an opening brace `{` and a closing brace `}` . Then write the parameters before the arrow `->` and the body after the arrow.

Once you’ve assigned a lambda to a variable, you can call it using the variable’s name. Listing 7.21 and Listing 7.22 accomplish the same thing, but the latter does it more concisely.

Both traditional functions and lambdas have parameters and a body, and evaluate to some kind of result. However, unlike traditional functions, the lambda itself does not have a name. Sure, you can choose to assign it to a variable that has a name, but the lambda itself is nameless.

The lambda in Listing 7.22 indicates that the `price` parameter has a type of `Double`. Most of the time, however, Kotlin can use its type inference to figure it out. For example, we can rewrite that listing and omit the parameter’s type in the lambda:

``val applyDiscount: (Double) -> Double = { price -> price - 5.0 }``

Kotlin knows that `price` must be a `Double`, because that’s what `applyDiscount`’s type says it must be. Similarly, the result of the lambda has to match.

So, lambdas are a concise way of creating a function right in the middle of an expression. Our lambda above is pretty small already, but we can make it even more concise!

## The Implicit `it` parameter

In cases where there’s only a single parameter for a lambda, you can omit the parameter name and the arrow. When you do this, Kotlin will automatically make the name of the parameter `it`. Let’s rewrite our lambda to take advantage of this:

``val applyDiscount: (Double) -> Double = { it - 5.0 }``

The code here is incredibly more concise than the original `discountFiveDollars()` function!

The implicit `it` parameter is used often in Kotlin, especially when the lambda is small, like this one. In cases when the lambda is longer, as we’ll see in a moment, it can be a good idea to give the parameter a name explicitly. In future chapters, we’ll also see cases where lambdas are nested inside other lambdas, which is another situation where explicit names are preferred. In many cases, though, the implicit `it` parameter can make your code easier to read.

Assigning a lambda to a variable can be helpful, but things get even more interesting when we start using lambdas with higher-order functions!

## Lambdas and Higher-Order Functions

### Passing Lambdas as Arguments

As we learned above, higher-order functions are those that have a function as an input (i.e., parameter) or an output (i.e., the result). Here’s the code from Listing 7.16 and Listing 7.17 above, where we used function references to pass functions as arguments to the `calculateTotal()` function:

``````fun calculateTotal(
initialPrice: Double,
applyDiscount: (Double) -> Double
): Double {
// Apply coupon discount
val priceAfterDiscount = applyDiscount(initialPrice)
// Apply tax
val total = priceAfterDiscount * taxMultiplier

}

fun discountFiveDollars(price: Double) = price - 5.0
fun discountTenPercent(price: Double): Double = price * 0.9
fun noDiscount(price: Double) = price

val withFiveDollarsOff = calculateTotal(20.0, ::discountFiveDollars) // \$16.35
val withTenPercentOff  = calculateTotal(20.0, ::discountTenPercent)  // \$19.62
val fullPrice          = calculateTotal(20.0, ::noDiscount)          // \$21.80``````

It’s easy to call `calculateTotal()` with a lambda instead of a function reference. Let’s rewrite the last few lines of the code above to use lambdas. We’ll just take the body from each corresponding function and write it as a lambda instead:

``````val withFiveDollarsOff = calculateTotal(20.0, { price -> price - 5.0 }) // \$16.35
val withTenPercentOff  = calculateTotal(20.0, { price -> price * 0.9 }) // \$19.62
val fullPrice          = calculateTotal(20.0, { price })                // \$21.80``````

In cases where function’s last parameter is a function type, you can move the lambda argument outside of the parentheses to the right, like this:

``````val withFiveDollarsOff = calculateTotal(20.0) { price -> price - 5.0 }
val withTenPercentOff  = calculateTotal(20.0) { price -> price * 0.9 }
val fullPrice          = calculateTotal(20.0) { price -> price }``````

We’re still sending two arguments to `calculateTotal()`. The first is inside the parentheses, and the second is outside to the right.

In Kotlin, writing the lambda outside of the parentheses like this is called trailing lambda syntax. Regardless of whether you put that last lambda argument inside the parentheses or outside, it works exactly the same. Kotlin developers usually prefer trailing lambdas, though.

Trailing lambda syntax is even more fun when the lambda is the only argument that you’re passing to the function, because then you can omit the parentheses completely!

For example, here’s a higher-order function with a single parameter, which has a function type:

``````fun printSubtotal(applyDiscount: (Double) -> Double) {
val result = applyDiscount(20.0)
val formatted = "\$%.2f".format(result)
println("A \$20.00 haircut will cost you \$formatted before tax.")
}``````

When calling `printSubtotal()`, no parentheses are needed!

``````printSubtotal { price -> price - 5.0 }
printSubtotal { price -> price * 0.9 }``````

In addition to using lambdas as arguments, we can also use them as function results!

### Returning Lambdas as Function Results

Here’s the code from Listing 7.18 above, where we returned function references:

``````fun discountForCouponCode(couponCode: String): (Double) -> Double = when (couponCode) {
"FIVE_BUCKS" -> ::discountFiveDollars
"TAKE_10"    -> ::discountTenPercent
else         -> ::noDiscount
}``````

We can very easily replace these function references with lambdas, just as we did for the function arguments in Listing 7.27.

``````fun discountForCouponCode(couponCode: String): (Double) -> Double = when (couponCode) {
"FIVE_BUCKS" -> { price -> price - 5.0 }
"TAKE_10"    -> { price -> price * 0.9 }
else         -> { price -> price }
}``````

## Lambdas with Multiple Statements

So far, the lambdas that we’ve used have contained only one simple expression each.

Sometimes you need a lambda that has multiple statements in it. To do this, simply put each statement on a separate line, as you would inside any other function. Unlike a regular function, though, you won’t use the return keyword to return your result. Instead, the very last line of the lambda will be the result of the call.

For example, we might want to print some debugging information inside our lambda that calculates the five-dollars-off coupon:

``````val withFiveDollarsOff = calculateTotal(20.0) { price ->
val result = price - 5.0
println("Initial price: \$price")
println("Discounted price: \$result")
result
}``````

When we’ve got a lambda that spans multiple lines like this, it’s conventional to put the parameters and arrow on the same line as the opening brace, as seen above. Here’s the same code, with some callouts indicating each part.

Before we wrap up this chapter, we’ve got one more concept to cover - closures!

## Closures

Bert’s salon is doing great now. He’s easily able to calculate the customers’ totals, even when they have different coupons. Let’s take a look at his code, including `calculateTotal()`, `discountForCouponCode()`, and how he ends up calling them to get the total.

``````fun calculateTotal(
initialPrice: Double,
applyDiscount: (Double) -> Double
): Double {
// Apply coupon discount
val priceAfterDiscount = applyDiscount(initialPrice)
// Apply tax
val total = priceAfterDiscount * taxMultiplier

}

fun discountForCouponCode(couponCode: String): (Double) -> Double = when (couponCode) {
"FIVE_BUCKS" -> { price -> price - 5.0 }
"TAKE_10"    -> { price -> price * 0.9 }
else         -> { price -> price }
}

val initialPrice = 20.0
val couponDiscount = discountForCouponCode("FIVE_BUCKS")
val total = calculateTotal(initialPrice, couponDiscount)``````

Bert noticed that when he introduces a new coupon, he needs to write another lambda. For example, if he adds a new coupon for nine dollars off, and another one for fifteen percent off, he would need to write a few more lambdas, like this:

``````fun discountForCouponCode(couponCode: String): (Double) -> Double = when (couponCode) {
"FIVE_BUCKS" -> { price -> price - 5.0 }
"NINE_BUCKS" -> { price -> price - 9.0 }
"TAKE_10"    -> { price -> price * 0.9 }
"TAKE_15"    -> { price -> price * 0.85 }
else         -> { price -> price }
}``````

That’s not too bad, actually, but he decided he could make one last small improvement. There are really two main categories of coupons - dollar amount and percentages. He wrote these two functions to match the two categories of coupons that he identified:

``````fun dollarAmountDiscount(dollarsOff: Double): (Double) -> Double =
{ price -> price - dollarsOff }

fun percentageDiscount(percentageOff: Double): (Double) -> Double {
val multiplier = 1.0 - percentageOff
return { price -> price * multiplier }
}``````

It’s important to note that these two functions do not calculate the discount themselves. Instead, they create functions that calculate the discount. This is a little easier to see in `percentageDiscount()`, where we’re using an explicit `return` keyword rather than an expression body.

Another neat thing here is that these lambdas use variables that are defined outside of the lambda body. The first one uses the `dollarsOff` variable (a parameter of the wrapping function), and the second uses the `multiplier` variable. When a lambda uses a variable that’s defined outside of its body like this, it’s sometimes referred to as a closure.

Now, creating a new coupon is easy. Instead of writing the lambda inline in `discountForCouponCode()`, Bert can just call either `dollarAmountDiscount()` or `percentageDiscount()` to create the lambda for him.

``````fun discountForCouponCode(couponCode: String): (Double) -> Double = when (couponCode) {
"FIVE_BUCKS" -> dollarAmountDiscount(5.0)
"NINE_BUCKS" -> dollarAmountDiscount(9.0)
"TAKE_10"    -> percentageDiscount(0.10)
"TAKE_15"    -> percentageDiscount(0.15)
else         -> { price -> price }
}``````

## Summary

Congratulations! Lambdas can be a tough concept for many programmers who haven’t used them before. If you still feel a little unsure about them, it’s completely fine. We’ll use them a lot in upcoming chapters, and you’ll get more familiar with them as you go.

In this chapter, you learned about:

Throughout this chapter, we’ve seen some simple use cases for lambdas, but they really shine when used with collections. In the next chapter, we’ll introduce collections, and we’ll see how we can use lambdas to do all sorts of fun things with them!

Thanks to James Lorenzen for reviewing this chapter!

1. Note, however, that you cannot use named arguments when you call a function using the variable’s name. [return]