Kotlin Tutorial · Advanced Kotlin · Lesson 28 of 31

Kotlin Context Parameters

Pass dependencies such as a logger or a transaction implicitly with context parameters, stable since Kotlin 2.4.

Create a free account to save this page, take notes and track your progress. Sign in

Implicit dependencies

Some values are needed by many functions (a logger, a database transaction, a user session). Passing them as ordinary parameters through every call is noisy. Context parameters declare them once: context(logger: Logger) fun .... A caller provides the context with with(value) { } or by being in a function that has the same context itself.

Context parameters became stable in Kotlin 2.4 (they replace the older experimental context receivers).

Context parameters
interface Logger { fun log(message: String) }

class ConsoleLogger(private val prefix: String) : Logger {
    override fun log(message: String) = println("[$prefix] $message")
}

context(logger: Logger)
fun reserveStock(sku: String) {
    logger.log("reserved $sku")
}

context(logger: Logger)
fun placeOrder(id: Int, skus: List<String>) {
    logger.log("placing order $id")
    skus.forEach { reserveStock(it) }      // the context is passed on implicitly
}

fun main() {
    with(ConsoleLogger("orders")) {
        placeOrder(42, listOf("mug", "teapot"))
    }
}

Output

[orders] placing order 42
[orders] reserved mug
[orders] reserved teapot

Run this on your computer — see “Get Started” for setup.

Test yourself

How does a caller supply a context parameter?

  1. As the first normal argument
  2. By calling inside a scope that provides it, e.g. with(value) { }
  3. Through a global variable
  4. With an annotation
Show answer

Answer: By calling inside a scope that provides it, e.g. with(value) { }

Was this page helpful?