What are Lambdas and Higher Order Functions in Kotlin and How Can You Use Them?
Tags: kotlin, tutorial, beginners, lambda
Published: 2022-09-14 06:07:09

Lambdas are widely used in Kotlin so you've most likely come across them, but if you're like me you might be asking, "What exactly is a Lambda? What does it do and how can I use them?"

This article attempts to answer those questions. Specifically:

- What a lambda is
- How to write a lambda (in other words, the syntax of a lambda)
- What a higher order function is and how lambdas are used in higher order functions.

## So, what is a lamda?

The simple answer is that lambdas are functions. But more specifically, a lambda is _a function_ that is _written as an expression_, and that is _not declared using the fun keyword_.

Here is an example of a regular function:

```kotlin
fun greeting() {
  println("Hello World!")
}
```

The same function can be written as a lambda:

```kotlin
val greeting = { println("Hello World!")}
```

You can call the lambda function by using the variable name followed by parentheses: `greeting()`.

```kotlin
val greeting = { println("Hello World!") }

// In the main function:
greeting() // prints: Hello World!
```

Note: you can also call the lambda function by using `greeting.invoke()`

Great, now that you know a bit about what a lambda is, we will have a look at how to write (and read) a lambda in the next section.

## How to write a lambda? The syntax.

You can write a lambda within curly braces. The parameters are separated from the function body by an arrow. So the parameters are written first, then an arrow and then the function body.

Extending our `greeting` example, let's give it one parameter so you can see the syntax of a lambda with parameters:

```kotlin
val greeting = { name: String -> println("Hello, $name")}

// In the main function:
greeting("Sam") // prints: Hello, Sam
```

### Function Types

Since Kotlin is a statically typed language, every variable must have a type. In the above example, the `greeting` variable is of a _function type_ because it holds a function (since a lambda is a function after all). Variables that hold lambdas are of a _function type_.

Kotlin can infer the function type implicitly, but you can also write it explicitly.

If you were to write out the full syntax of `greeting`, it would look like:

```kotlin
val greeting: (String) -> Unit = { name: String -> println("Hello, $name")}
```

The above reads as:

- `greeting` is a variable of a function type
- it will hold a function
- the function it holds will take a String argument and return Unit.

### Short-hand syntax for lambdas

There are three simplifications we can make to the lambda syntax, which makes it easier to read.

1) When the variable declaration has an explicitly declared function type, for example a function type that takes a String and returns Unit (like in the example above), you don't have to explicitly define the parameter of the lambda as being of String type. 
This is because Kotlin already knows that the lambda will have a String type parameter since it has been explicitly defined in the variable declaration. This is easier to illustrate through code:

```kotlin
val greeting: (String) -> Unit = { name: String -> println("Hello, $name")}

/* We don't need to explicitly say that the
name parameter will be of String type.
We can simplify it to:
*/

val greeting: (String) -> Unit = { name -> println("Hello, $name")}
```

2) If the lambda has only one parameter, you don't have to write the parameter. Instead, there is an `it` keyword that you can use to refer to the parameter. So you can further simplify `greeting` to:

```kotlin
val greeting: (String) -> Unit = { println("Hello! $it")}
```

3) You don't need to use the `return` keyword. This is because the last expression within the lambda's body is treated as the return value. To illustrate, let's change our `greeting` function to return a String:

```kotlin
val greeting: (String) -> String = {"Hello, $it"}
greeting("Sam") // Will return "Hello, Sam" even though the return keyword was not used in greeting.
```

## What is a higher order function?

Higher order functions are functions and take a function as an argument. Phew, so many "functions" there!

_Note:_ When writing higher order functions, it is best practice in Kotlin to have the function argument as the last parameter.

An example of a higher order function:

```kotlin
fun createLongGreeting (firstSentence: String, secondSentence: String, operation: (String) -> String) : String {
	return "${operation(firstSentence)} $secondSentence"
}
```

In the above example, `createLongGreeting` is a higher order function that creates and returns a string template using:

- the result of calling an operation (function) on the first sentence, and
- the second sentence

It takes 3 arguments:

1. A string (the `firstSentence` parameter)
2. A string (the `secondSentence` parameter)
3. A function (the `operation` parameter)

## Okay, so how can lambdas help you when it comes to higher order functions?

Since higher order functions take another function as an argument, you need to be able to pass functions to them. If you try to pass a regular function as the argument, Kotlin will throw an error because it will think you're trying to call the function instead of simply passing it in as an argument. For example if you try the following, it will give you an error:

```kotlin
fun partGreeting(name: String): String {
  return "${name}! It's has been a long time!"
}

createLongGreeting("Sam", "How are you?", partGreeting) // error: Function invocation 'partGreeting(...)' expected. No value passed for parameter 'name'
```

You need a way to easily pass functions as arguments to the higher order functions. And that's where lambdas come to the rescue.

### Passing in a lambda as a parameter to a higher order function

Lambdas allow you to easily pass functions as arguments.

Continuing with the example from above, you can pass a lambda directly into `createLongGreeting` as its last argument. The lambda must be one that takes a String as it's argument and returns a String.

```kotlin
// The createLongGreeting function
fun createLongGreeting (firstSentence: String, secondSentence: String, operation: (String) -> String) : String {
	return "${operation(firstSentence)} $secondSentence"
}

// In the main function:
// Calling createLongGreeting and passing a lambda directly to it as it's last argument.
val firstGreeting = createLongGreeting("Sam", "How are you?", { name -> "$name! It's been a long time!" })

println(firstGreeting) // Sam! It's been a long time! How are you?
```

Here is a breakdown of what is happening in the above example:

1. We call `createLongGreeting`, passing it:
   - "Sam" as it's first argument
   - "How are you?" as it's second argument
   - A lambda as it's third argument
2. `createLongGreeting` calls our lambda, passing it "Sam"
3. Our lambda returns a string: "Sam! It's been a longtime!"
4. `createLongGreeting` creates a string template, inserting the string returned from the lambda call ("Sam! It's been a longtime!") and the string we passed as the second argument ("How are you?")
5. `createLongGreeting` returns the string it created in step 4: "Sam! It's been a long time! How are you?"

### Trailing lambda syntax

To make our example easier to read, we can actually put the lambda outside the parenthesis:

```kotlin
val firstGreeting = createLongGreeting("Sam", "How are you?") { name -> "$name! It's been a long time!" }
```

This is known as a trailing lambda syntax.

### Assigning a lambda to a variable and passing that variable to the higher order function

Another way we can use lambdas with higher order functions is by assigning the lambda to a variable and passing that variable as an argument to the higher function.

First, we need to make a lambda and assign it to a variable:

```kotlin
val greeting: (String) -> String = {"Hello, $it!"}
```

Next, we pass `greeting` to `createLongGreeting`. Note that we don't call `greeting` directly. We just **pass** it to `createLongGreeting`. It's `createLongGreeting` that calls `greeting` when making its string template.

```kotlin
// The createLongGreeting function:
fun createLongGreeting (firstSentence: String, secondSentence: String, operation: (String) -> String) : String {
    return "${operation(firstSentence)} $secondSentence"
}

// Our lambda - the greeting function:
val greeting: (String) -> String = {"Hello, $it!"}

// In the main function, call createLongGreeting and pass it greeting as it's last argument:
val secondGreeting = createLongGreeting("Sam", "How are you?", greeting)
println(secondGreeting) // Hello, Sam! How are you?
```

As mentioned earlier, if `greeting` were a regular function (or a single line function) instead of a lambda, we could not pass it to `createLongGreeting` as above, because Kotlin will think that we are trying to call greeting and give an error. But there is a way to pass a regular function as an argument: we can use the `::` symbol to pass the function as a reference.

In the example below, `greeting` is written as a single line function and passsed to `createLongGreeting` as a reference:

```kotlin
fun greeting(name: String) = "Hello, $name!"

// In the main function:
val secondGreeting = createLongGreeting("Sam", "How are you?", ::greeting)
```

### Bonus tip: you could capture a user's input, clean it up and use it in `createLongGreeting`:

First, create a function to clean the user's input data:

```kotlin

val cleanUserInput: (String) -> String = { userInput -> userInput.replace(userInput[0], userInput[0].uppercaseChar()).trim()
}
```

Then, in the main function, prompt the user to enter their name and assign it to a variable:

```kotlin
print("Please enter your name: ")
val usersName = readln()
```

Finally, call `createLongGreeting`, passing it the input from the user, the string "Good to see you!" and the `cleanUserInput` function. The `cleanedUserInput` function will be called within `createLongGreeting` to clean the input from the user:

```kotlin
val thirdGreeting = createLongGreeting(usersName, "Good to see you!", cleanUserInput)
println(thirdGreeting) // if the user inputs "hallie", the output would be "Hallie Good to see you!"
```

So there you have it - now you know more about:

- what lambdas are,
- how they look like,
- how to write them,
- what higher order functions are,
- and how you can use a lambda to pass a function as an argument to a higher order function.

Thanks for reading!