Menu
Coddy logo textTech

lazy and lateinit

Part of the Object Oriented Programming section of Coddy's Kotlin journey. Lesson 10 of 57.

by lazy { ... } delays the computation of a val until it is first read, then remembers the result. It fits values that are expensive or not always needed:

class Report(val rows: List<Int>) {
    val summary: String by lazy {
        println("computing summary")
        "total ${rows.sum()}"
    }
}

Inside main:

val r = Report(listOf(3, 4))
println("created")
println(r.summary)
println(r.summary)

Output:

created
computing summary
total 7
total 7

The block runs once: the second read above used the stored result. Unlike a custom getter, which runs on every read, lazy computes once and caches:

class Demo {
    var reads = 0
    val viaGetter: Int
        get() { reads++; return 42 }
    val viaLazy: Int by lazy { reads++; 42 }
}

Inside main:

val d = Demo()
repeat(3) { d.viaGetter; d.viaLazy }
println(d.reads)

Output:

4

lateinit var declares a non-null property that is assigned later, after construction, for example by a setup method. Reading it before it is assigned throws an exception, and ::name.isInitialized checks it:

class Screen {
    lateinit var title: String

    fun load(t: String) { title = t }
    fun ready() = ::title.isInitialized
}

Inside main:

val s = Screen()
println(s.ready())
s.load("Home")
println(s.ready())
println(s.title)

Output:

false
true
Home

Prefer plain initialization when the value is known at construction. Use lazy for a costly val that may not be needed, and lateinit only for a var whose value truly arrives later; lateinit does not work with Int, Boolean or other primitive types.

val config by lazy { loadConfig() }     // computed on first use, once
lateinit var user: User                 // assigned after construction
// lateinit var count: Int              // error: not allowed on primitive types
challenge icon

Challenge

Easy

Complete the class Document(val text: String). Add wordCount as a lazy property that counts the words (separated by single spaces) and records each computation by adding 1 to computations, and a lateinit var author: String with a method credit() that returns by Ada or by unknown when the author has not been set.

The supplied code reads the text, reads wordCount three times, sets the author when a second line is present, and prints words 5, computed 1, by Ada.

Your code goes in Document.kt. Main.kt holds the supplied input/output code and cannot be edited.

Try it yourself

fun main() {
    // Supplied input/output code: keep it as it is
    val input = generateSequence(::readLine).toList()
    val doc = Document(input[0])
    val reads = List(3) { doc.wordCount }
    val words = reads.first()
    if (input.size > 1) doc.author = input[1]
    println("words $words, computed ${doc.computations}, ${doc.credit()}")
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Kotlin playground