I found a compiler bug

A few years ago, I gave programming language Kotlin a try, liked what I saw, even taught it for a short period as part of a course on Android mobile app development. Then, for various reasons, I put it to one side.

The recent release of Kotlin 2.0.0, with its brand-new K2 compiler, prompted me to revisit the language and get reacquainted with it. But it seems I may have uncovered a bug in that shiny new compiler.

The issue concerns properties in classes. A property is essentially an abstraction of a field and its getter & setter methods. Syntax-wise, it may look like you are accessing a field directly, but in reality the field is hidden and the getter or setter is called implicitly, to provide the appropriate access.

Sometimes, you want a property whose value needs to vary, but only in a very specific manner dictated by the class itself and not by client code. It such situations, you declare it as a var, so it can be reassigned a new value by other code within the class, but you make its setter private so that client code cannot perform a reassignment on it.

Here's an example of a class which has such a property, along with a small program that tests it.

class Car {
    val fuelConsumption = 10

    var fuel = 100
        private set

    fun travel(distance: Int) {
        println("Travelling $distance units...")
        fuel -= fuelConsumption * distance
    }
}

fun main() {
    val car = Car()
    println("Initial fuel: ${car.fuel}")
    car.travel(2)
    println("Final fuel: ${car.fuel}")

    // Compiler error in 1.9.24 and 2.0.0
    //car.fuel = 70

    // Compiler error in 1.9.24 but not in 2.0.0!
    car.fuel -= 10

    println("Fuel now ${car.fuel}")
}

In this example, a car's fuel level can only vary as a result of it travelling. Programs that manipulate a Car object cannot give the fuel property an arbitrary value - at least, they shouldn't be able to do so. It looks like version 1.9.24 of the compiler enforces this restriction correctly, but the new K2 compiler prevents only direct assignment; it fails to prevent the use of operators like += and -= that increment or decrement the property.

I spent a good hour scratching my head over this, trying to figure out whether I was misunderstanding what private setters were supposed to do. Only after testing the code in the previous version of Kotlin, which doesn't use K2, did I start to think that maybe K2 was at fault here.

I still can't quite believe that such a basic thing slipped past alpha and beta testing into the final release, but it's clearly a regression. I've submitted a bug report, so let's see what happens next.

More from Nick
All posts