Even the variables in Kotlin are supercharged!

Let’s start with a simple data class and see how the variables in there behave.

data class Student(val name: String, val age: Int, val subjects: ArrayList<String>)

To use the variables in this class, Kotlin let’s you directly use the dot notation for accessing.


>>> val s1 = Student("Keith Hernandez", 21, arrayListOf("Mathematics", "Social Studies"))
>>> println(s1.name)

Keith Hernandez

>>> println(s1) // data classes automatically generate `toString` and `hashCode`

Student(name=Keith Hernandez, age=21, subjects=[Mathematics, Social Studies])

For Java callers, Kotlin also generates getters and setter methods.

final Student s1 = new Student("Keith Hernandez", 21, arrayListOf("Mathematics", "Social Studies"));
System.out.println(s1.getName());
System.out.println(s1);

The same properties apply to variables in non-data classes as well.


>>> class Item(id: Int, name: String) {

...     val itemId = id
...     val itemName = name
... }

>>> val item = Item(0, "Bricks")
>>> println(item.itemId)

0

>>> println(item)

Line_4$Item@46fb460a

>> >

As you can notice, the toString implementation is not identical to our data classes but that’s a topic for another post. Back to variables!

Customizing getters and setters

While Kotlin creates getters and setters automatically, we can customize their behavior.

class Item(id: Int, name: String) {
    var itemId = id
    var itemName = name
    var currentState: Pair<Int, String> = Pair(itemId, itemName)
        set(value) {
            itemId = value.first
            itemName = value.second
            field = value
        }
    override fun toString() : String {
        return "id=$itemId,name=$itemName"
    }
}

Let’s take this for a spin in the Kotlin REPL and see how our currentState field behaves.

>>> val item = Item(0, "Nails")
>>> println(item)
id=0,name=Nails
>>> item.currentState = Pair(1, "Bricks")
>>> println(item)
id=1,name=Bricks

Notice how setting a new value to currentState mutates the other variables as well? That’s because of our custom setter. These setters are identical to a normal top-level function except a reference to the field in question is available as the variable field for manipulation.

Visibility modifiers

Kotlin’s visibility modifiers aren’t very well explained. There’s the standard public, private and protected, but also the new inner and internal. I’ll attempt to fill in those gaps.

inner

inner is a modifier that only applies to classes declared within another one. It allows you to access members of the enclosing class. A sample might help explain this better.

class Outer {
    private val bar: Int = 1
    inner class Inner {
        fun foo() = bar
    }
}

val demo = Outer().Inner().foo() // == 1

The keyword this does not behave as some would normally expect in inner classes, go through the Kotlin documentation for this here and I’ll be happy to answer any further questions :)

internal

internal applies to methods and properties in classes. It makes the field/method ‘module-local’, allowing it to be accessed within the same module and nowhere else. A module in this context is a logical compilation unit, like a Gradle subproject.

That’s all for today! Hope you’re liking the series so far. I’d love to hear feedback on what you want me to cover next and how to improve what I write :)