Part of Github Copilot with Kotlin

Kotlin with Copilot: Create a lambda function to add 2 numbers

Sandy LaneSandy Lane

Video: Kotlin with Copilot: Create a lambda function to add 2 numbers 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 Add Two Numbers

val add: (Int, Int) -> Int = { a, b -> a + b }. The two-arg version of the doubler. The smallest possible "operation" lambda.

A small puzzle: store an addition operation as a lambda. Combines episode 25 (higher-order functions) and 29 (one-line lambdas).

The Copilot prompt

fun main() {
  // Lambda to add two integers
  val add: (Int, Int) -> Int =

Copilot generates:

val add: (Int, Int) -> Int = { a, b -> a + b }

val result = add(5, 7)
println("Sum: $result")   // 12

Walkthrough

(Int, Int) -> Int — takes two Ints, returns Int. The lambda body a + b is the entire computation. No explicit return; single-expression body.

Calling: add(5, 7) returns 12.

Versus a regular function

fun add(a: Int, b: Int): Int = a + b

Same logic, different shape. The named function:

  • Can be called from anywhere (after declaration).
  • Cleaner stack traces ("called add(5, 7)" vs "called (5, 7)").
  • Slightly faster (JVM can inline named functions more aggressively, depending on context).

The lambda:

  • Can be passed around, stored, returned.
  • Captures local variables (closure).
  • Used as a parameter to higher-order functions.

For a fixed operation, name the function. For a slot you'll fill in later, use a lambda.

Operator references

For the common operators, you don't even need a lambda:

val nums = listOf(1, 2, 3, 4, 5)
val sum = nums.reduce { a, b -> a + b }   // 15
val sum2 = nums.reduce(Int::plus)          // 15 — operator reference

Int::plus is the function reference for the + operator. Same effect as { a, b -> a + b }. Idiomatic when the lambda is just an operator.

Defining your own operator

For custom types, define operator overloads:

data class Money(val cents: Int) {
  operator fun plus(other: Money) = Money(cents + other.cents)
  operator fun minus(other: Money) = Money(cents - other.cents)
}

val a = Money(100)
val b = Money(50)
println(a + b)   // Money(cents=150)

operator fun plus(other: T) makes a + b desugar to a.plus(b). Same for minus, times, div, rem, compareTo, equals, etc.

Now Money::plus is a function reference too:

val total = listOf(Money(100), Money(50), Money(25)).reduce(Money::plus)

Storing operations in a map

val ops: Map<String, (Int, Int) -> Int> = mapOf(
  "+" to { a, b -> a + b },
  "-" to { a, b -> a - b },
  "*" to { a, b -> a * b },
  "/" to { a, b -> a / b },
  "%" to { a, b -> a % b },
)

fun calc(op: String, a: Int, b: Int): Int? = ops[op]?.invoke(a, b)

println(calc("+", 5, 3))   // 8
println(calc("*", 4, 6))   // 24

A simple calculator. The map dispatches by operator name. Adding "**" (power) is one new entry — no when-block to maintain.

Lambdas with side effects

val log: (Int, Int) -> Int = { a, b ->
  println("Computing $a + $b")
  a + b
}

val result = log(5, 7)
// Prints: "Computing 5 + 7"
// result = 12

Multiple statements in a lambda — the last expression is the return value. The println runs; the a + b is returned.

This is the simplest form of "decorator" — wrap a function with logging.

Currying (manually)

Kotlin doesn't have built-in currying, but you can simulate it with closures:

val add: (Int) -> (Int) -> Int = { a -> { b -> a + b } }

val add5 = add(5)         // (Int) -> Int — partially applied
println(add5(3))           // 8
println(add5(10))          // 15

add(5) returns a function that adds 5 to its argument. The captured a = 5 lives as long as the returned function does.

Useful for partial application — fix some arguments early, take the rest later.

Variadic addition

For "add an arbitrary number of integers":

fun addAll(vararg nums: Int): Int = nums.sum()

println(addAll(1, 2, 3, 4, 5))   // 15

vararg parameters become an IntArray. .sum() is the built-in.

For lambdas, no vararg — they're fixed-arity:

val addAllLambda: (IntArray) -> Int = { it.sum() }
println(addAllLambda(intArrayOf(1, 2, 3, 4, 5)))   // 15

Pass an array explicitly.

Common mistakes

Wrong number of params in the call. add(5) errors when add: (Int, Int) -> Int. Match the arity.

Using it for a 2-arg lambda. { it + it } is wrong (no implicit it for multi-arg). Use names: { a, b -> a + b }.

Forgetting type annotation when needed. val add = { a, b -> a + b } doesn't compile — Kotlin can't infer a's and b's types. Add either variable type or parameter types.

Returning Unit by accident. val add: (Int, Int) -> Int = { a, b -> println(a + b) } returns Unit (println's return). Last expression must produce the right type.

Treating + as something special. + between ints is just Int.plus(Int). Same machinery as any operator.

What's next

Episode 31: Lambda to square a number. Single-arg variant — same shape, simpler body.

Recap

val add: (Int, Int) -> Int = { a, b -> a + b }. Single-expression body, no return. Operator references like Int::plus work where the lambda is just an operator. Custom types can operator fun plus(...) to participate. Multi-statement lambdas: last expression is the return. Currying via closures: (Int) -> (Int) -> Int. For variadic, use a regular function with vararg.

Next episode: square lambda.

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.