Part of Github Copilot with Kotlin

Kotlin with copilot: Use lambda function to print out a name

Sandy LaneSandy Lane

Video: Kotlin with copilot: Use lambda function to print out a name by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

Kotlin: Lambda to Print a Name

val printName: (String) -> Unit = { name -> println("Name: $name") }. The single-parameter version of episode 26 — the simplest possible lambda.

A small step from the two-arg version. One parameter, one side effect.

The Copilot prompt

fun main() {
  // Lambda that takes a name and prints it
  val printName: (String) -> Unit =

Copilot generates:

val printName: (String) -> Unit = { name ->
  println("Name: $name")
}

printName("Alice")   // Name: Alice

Implicit it for single-parameter lambdas

For lambdas with exactly one parameter, you can omit the parameter name and use it:

val printName: (String) -> Unit = { println("Name: $it") }

it is the implicit name of the single parameter. Reads cleanly:

listOf(1, 2, 3).forEach { println(it) }
listOf("a", "b", "c").map { it.uppercase() }

forEach and map take single-arg lambdas; it is their parameter.

For multi-parameter lambdas ({ x, y -> ... }), there's no it — explicit names required.

When to name the parameter

it is fine for short lambdas. For longer or nested code, name explicitly:

// Clear:
val printName: (String) -> Unit = { name -> println("Name: $name") }

// Less clear with nesting:
list.map { item ->
  item.children.map { child ->
    "${item.name} -> ${child.name}"
  }
}

// Confusing — which `it` is which?
list.map { it.children.map { ... } }

Rule of thumb: explicit name when nested or when it doesn't read naturally.

forEach: the canonical use

forEach takes a (T) -> Unit lambda — apply a side-effecting function to each element:

val names = listOf("Alice", "Bob", "Charlie")
names.forEach { println("Hello, $it!") }
// Hello, Alice!
// Hello, Bob!
// Hello, Charlie!

forEach is for side effects — print, write, send to API. For transformations, use map. For filtering, use filter. Each tool has a purpose.

forEachIndexed: with the index

names.forEachIndexed { index, name ->
  println("$index: $name")
}
// 0: Alice
// 1: Bob
// 2: Charlie

When you need both the position and the value. Note the lambda has two parameters now, so it doesn't apply.

Lambdas as arguments

fun greet(name: String, formatter: (String) -> String) {
  println(formatter(name))
}

greet("Alice", { name -> "Hello, $name!" })
// Or with trailing-lambda syntax:
greet("Alice") { name -> "Hello, $name!" }
// Or with implicit it:
greet("Alice") { "Hello, $it!" }

Three increasingly idiomatic forms of the same call.

Why store a lambda in a variable?

For one-off use, a regular function is fine. For:

  • Conditional behaviour. Pick the function at runtime based on user choice.
  • Closures. Capture state at creation time:
fun makeGreeter(greeting: String): (String) -> String {
  return { name -> "$greeting, $name!" }
}

val hi = makeGreeter("Hi")
val hello = makeGreeter("Hello")
println(hi("Alice"))     // "Hi, Alice!"
println(hello("Bob"))    // "Hello, Bob!"

Each makeGreeter call returns a new function with its own captured greeting.

  • Passing to async code. Callbacks, event handlers.

Lambda vs anonymous function

Kotlin has two anonymous-function syntaxes:

// Lambda
val printName1: (String) -> Unit = { name -> println(name) }

// Anonymous function (more verbose, more flexible)
val printName2 = fun(name: String): Unit { println(name) }

The lambda is shorter. The anonymous-function form lets you return early without labels:

val firstThree = listOf(1, 2, 3, 4, 5).filter(fun(x: Int): Boolean {
  if (x > 3) return false
  return true
})

Inside a lambda, return returns from the enclosing function, not the lambda. To return from the lambda only, use return@filter. Anonymous functions don't have that confusion.

For 99% of cases, lambdas are clearer. Anonymous functions are an escape hatch.

Common mistakes

Trying it in multi-arg lambdas. Doesn't exist. { x, y -> x + y } requires names.

return from a lambda. Returns from the outer function. To return from the lambda only, use return@label:

list.forEach {
  if (it < 0) return@forEach   // skip this iteration
  println(it)
}

Storing function calls instead of functions. val x = printName("Alice") calls and stores Unit. Use val x = ::printName or assign a lambda.

Lambda with side effects in map. list.map { println(it) } works but is misleading — map is for transformations. Use forEach for side effects.

Implicit it shadowing outer it. Nested lambdas with implicit it confuse readers. Always name the parameter when nesting.

What's next

Episode 28: List of 10 numbers, lambda to find evens. Combines (1..10).toList() with filter { it % 2 == 0 }.

Recap

Single-parameter lambdas use it as the implicit name (or explicit name if clearer). forEach { println(it) } for side-effecting iteration. forEachIndexed if you need the position. Anonymous-function syntax (fun(x): T { ... }) exists but is rarely used. Use trailing-lambda syntax fn(args) { lambda } for readability. Side effects → forEach; transforms → map; predicates → filter.

Next episode: filter evens from 1..10.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.