0Pricing
Kotlin Academy · Lesson

tailrec Functions

Optimize recursion.

tailrec Functions is a free Kotlin Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is Tail Recursion?

A function is tail-recursive when its recursive call is the very last operation. Kotlin can then optimize it into a loop, avoiding stack overflow.

tailrec fun countdown(n: Int) {
    if (n < 0) return
    println(n)
    countdown(n - 1)
}

fun main() {
    countdown(3)
}

The tailrec Modifier

Add the tailrec modifier and the compiler rewrites the recursion as iteration, using constant stack space.

tailrec fun sum(n: Int, acc: Int = 0): Int {
    if (n == 0) return acc
    return sum(n - 1, acc + n)
}

fun main() {
    println(sum(100))
}

The Accumulator Pattern

To make recursion tail-form, carry results in an accumulator parameter so nothing remains to compute after the call.

tailrec fun factorial(n: Int, acc: Long = 1): Long {
    if (n <= 1) return acc
    return factorial(n - 1, acc * n)
}

fun main() {
    println(factorial(10))
}

Why the Call Must Be Last

If anything happens after the recursive call (like multiplying its result), the call is not in tail position and cannot be optimized.

tailrec fun length(s: String, acc: Int = 0): Int {
    if (s.isEmpty()) return acc
    return length(s.drop(1), acc + 1)
}

fun main() {
    println(length("hello"))
}

Non-Tail Recursion Counter-Example

This factorial is NOT tail-recursive because the multiply happens after the call returns. Marking it tailrec would warn.

fun badFactorial(n: Int): Long {
    if (n <= 1) return 1
    return n * badFactorial(n - 1)
}

fun main() {
    println(badFactorial(5))
}

Avoiding Stack Overflow

Deep recursion without tailrec can crash. With it, even large inputs run in constant stack space.

tailrec fun count(n: Int, acc: Int = 0): Int {
    if (n == 0) return acc
    return count(n - 1, acc + 1)
}

fun main() {
    println(count(100000))
}

Compiler Verification

If you mark a function tailrec but the call is not in tail position, the compiler emits a warning and does not optimize. Trust the warning.

tailrec fun gcd(a: Int, b: Int): Int {
    if (b == 0) return a
    return gcd(b, a % b)
}

fun main() {
    println(gcd(48, 18))
}

Tail Recursion vs Loop

A tailrec function compiles to roughly the same code as the equivalent loop, but expresses the algorithm recursively.

tailrec fun powerOfTwo(n: Int, acc: Long = 1): Long {
    if (n == 0) return acc
    return powerOfTwo(n - 1, acc * 2)
}

fun main() {
    println(powerOfTwo(10))
}

Multiple Parameters

Tail-recursive functions often pass along several state parameters, all updated in the recursive call.

tailrec fun fib(n: Int, a: Long = 0, b: Long = 1): Long {
    if (n == 0) return a
    return fib(n - 1, b, a + b)
}

fun main() {
    println(fib(20))
}

Reversing with tailrec

An accumulator can build up a result like a reversed string.

tailrec fun reverse(s: String, acc: String = ""): String {
    if (s.isEmpty()) return acc
    return reverse(s.drop(1), s.first() + acc)
}

fun main() {
    println(reverse("kotlin"))
}

A Practical Search

Iterative searches map cleanly to tail recursion.

tailrec fun indexOf(list: List<Int>, target: Int, i: Int = 0): Int {
    if (i >= list.size) return -1
    if (list[i] == target) return i
    return indexOf(list, target, i + 1)
}

fun main() {
    println(indexOf(listOf(5, 6, 7), 7))
}

Quick Check

Test your understanding of tailrec functions.

Recap

You learned tailrec functions:

  • tailrec converts tail-position recursion into a loop, avoiding stack overflow.
  • The recursive call must be the last operation.
  • Use an accumulator parameter to reach tail form.
  • The compiler warns when a function cannot be optimized.
tailrec fun sum(n: Int, acc: Int = 0): Int =
    if (n == 0) acc else sum(n - 1, acc + n)

fun main() {
    println(sum(50))
}

Frequently asked questions

Is the “tailrec Functions” lesson free?

Yes — the full text of “tailrec Functions” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.

What will I learn in “tailrec Functions”?

Optimize recursion. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “tailrec Functions” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Infix Functions
  2. Building DSL-like APIs
  3. tailrec Functions
  4. When to Use Each
← Back to Kotlin Academy