Search code examples
kotlinin-class-initialization

Why to put val or var in kotlin class constructors


Just learning Kotlin In the first code down below there is the val keyword right in the other code there is not, what is the different here if the val and var is omitted?

class Person(val firstName: String, val lastName: String) {
}

class Person(firstName: String, lastName: String) {
}

Solution

  • If you omit val or var in in a constructor, then the only places that can access these parameters are initialization statements that are evaluated at construction time. See https://kotlinlang.org/docs/reference/classes.html

    This is useful when you want to do something with a value before storing it. In Java you would put that code a constructor body

    class Person(firstName: String, lastName: String) {
        // directly in val / var declarations
        val firstName = firstName.capitalize()
        val lastName = lastName
    
        // in init blocks
        val fullName: String
        init {
            fullName = "$firstName $lastName"
        }
    
        // secondary constructors can only see their own parameters
        // and nothing else can access those
        constructor(fullName: String) : this("", fullName)
    }
    

    But it also works for delegation using by

    interface Named {
        fun getName(): String
    }
    class Human(private val fname: String, private val lname: String) : Named {
        override fun getName() = "$fname + $lname" // functions need val since
                                                   // value is resolved after construction
    }
    class Person2(firstName: String, lastName: String) : Named by Human(firstName, lastName)
    
    class Person3(human: Human) : Named by human {
        constructor(firstName: String, lastName: String): this(Human(firstName, lastName))
    }
    

    Or in property delegation

    class Person4(firstName: String, lastName: String) {
        val fullName: String by lazy { "$firstName $lastName" }
    }
    

    Note: the closure is captured at initialization time, the values are therefore still available when lazy evaluates eventually.