# Context Receivers in Kotlin: An Example

Context Receivers are a new feature introduced in Kotlin 1.6.20. They're useful for receiving the `context` from the call-site when a function is called. To understand it and its utility, let's first take a look at a similar feature available in the language.

### Extension Functions

In Kotlin, Extension functions have proven to be an extremely useful feature. They can be used to extend the functionality of a class without inheriting it, and prove extremely useful when you have to define utility methods.

Say you wanted to write a utility method that reverses an integer. You could write something like this:

```kotlin
fun reverse(number: Int): Int {
    var sum = 0
    var num = number
    while (num != 0) {
        sum = (sum * 10) + (num % 10)
        num /= 10
    }
    return sum
}

println(reverse(12345))
```

With extension functions, you can define an additional method on the `Int` the class itself, and call that on any integer you'd like:

```kotlin
fun Int.reverse(): Int {
    var sum = 0
    var num = this
    while (num != 0) {
        sum = (sum * 10) + (num % 10)
        num /= 10
    }
    return sum
}

println(12345.reverse())
```

When we're using Extension Functions, the object that it is being called upon is called the **receiver.**

### Limitation: Single Receiver

With extension functions, we can only use a single receiver at a time. There are some use cases that warrant the usage of 2 or more receivers.

As an example, consider the case where we're using [`StateFlow`](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow) instead of `LiveData` to make the UI reactive to state change. The correct method to collect a `StateFlow` in a `Fragment` looks like this:

```kotlin
viewLifecycleOwner.lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.state.collect {
            binding.toolbar.text = it.titleText
            // ...
        }
    }
}
```

This is rather verbose, and if the pattern is being used in several places, you'd obviously like to convert this to a utility function that'd make things simpler. A very simple definition is presented below:

```kotlin
fun Fragment.collectStateFlow(body: suspend CoroutineScope.() -> Unit) {
    viewLifecycleOwner.lifecycleScope.launch {
        repeatOnLifecycle(Lifecycle.State.STARTED) {
            body()
        }
    }
}

// In Fragment
collectStateFlow {
    viewModel.state.collect {
        binding.toolbar.text = it.titleText
        // ...
    }
}
```

What if we wanted to take this a step further, and eliminate the additional line to collect the `StateFlow` too? We can define an extension function on `Flow` or `StateFlow` that can collect emissions while handling the lifecycle under the hood. **Here's where we run into a problem.** If we define an extension function on `StateFlow`, it can *only* *receive* the `StateFlow`. In other words, only methods that can be called on a StateFlow will be inside the function, since it'll have the context of the `StateFlow` it has been called on. Hence, we'll have to pass the Fragment as an argument to the function:

```kotlin
fun <T> StateFlow<T>.collectWithLifecycle(fragment: Fragment, block: (T) -> Unit) {
    fragment.viewLifecycleOwner.lifecycleScope.launch {
        fragment.repeatOnLifecycle(Lifecycle.State.CREATED) {
            this@collectWithLifecycle.collect {
                block(it)
            }
        }
    }
}

// In Fragment
viewModel.state.collectWithLifecycle(this) {
    binding.toolbar.text = it.titleText
    // ...
}
```

Now that's neat. Looks a lot like the `observe` method of a `LiveData` right?

### Context Receivers

Being programmers, we have a bad habit of trying to write clever code, so your mind naturally wonders: What if we could have the `Fragment` context just be implicitly available in the function body? That'd be great. And that's exactly where Context Receivers help us. For a good explanation of how they work, see [this](https://kt.academy/article/fk-context-receivers). In short, using context receiver syntax, we can have as many receivers for our function as we'd like, meaning we can get any scope we want. Consider this example:

```kotlin
class A {
    val x = 10
}

class B {
    val y = 20
}

context(A, B)
fun printValues() { 
    println(x)
    println(y)
}

fun main() {
    A().apply {
        with(B()) {
            printValues()
        }
    }
}
```

No need to pass arguments. We can access `x` and `y` inside `printValues` since when we call it, contexts of both classes `A,` and `B` are available, and that's seemingly transferred to our method.

### Best version of our code using Context Receivers

To use Context Receivers on Android, add this to the `kotlinOptions` block in your app-level `build.gradle` file:

```kotlin
freeCompilerArgs = ["-Xcontext-receivers"]

// Overall
kotlinOptions {
    jvmTarget = '1.8'
    freeCompilerArgs = ["-Xcontext-receivers"]
}
```

Additionally, you need to be using **Kotlin 1.6.20 or higher.**

Once we've enabled the feature, we can write a utility method like this:

```kotlin
context(Fragment)
fun <T> StateFlow<T>.collectWithLifecycle(block: (T) -> Unit) {
    viewLifecycleOwner.lifecycleScope.launch {
        repeatOnLifecycle(Lifecycle.State.CREATED) {
            this@collectWithLifecycle.collect {
                block(it)
            }
        }
    }
}

// In Fragment
viewModel.state.collectWithLifecycle {
    binding.toolbar.text = it.titleText
    // ...
}
```

This eliminates all boilerplate we need to write while collecting a `StateFlow`.

> **Tip**: Instead of `StateFlow<T>`, use `Flow<T>` to use with all `Flow` derivates such as `SharedFlow` and `StateFlow`.
> 
> ---
> 
> **Tip:** To use with `Activity`, replace `Fragment` with `Activity` as the receiver in the code, and remove `viewLifecycleOwner` since it's not necessary with an `Activity`.
> 
> ---
> 
> **Tip:** Compose already has an API for this. [See here](https://medium.com/androiddevelopers/consuming-flows-safely-in-jetpack-compose-cde014d0d5a3).

Arrivederci!
