Properties vs fields

Before go ahead it is important to clarify the difference between fields and properties.

Field is just a class member variable that hold a value. It can be read-only or mutable and marked with any access modifier such as public or private .

Property is more complex element that contain a private field and accessors. By accessors I mean getter and setter. Property can also be read-only or mutable.

read-only property = private field + getter

mutable property = private field + getter + setter

The following code declares the Human class with the read-only age property that contains a getter implicitly:

class Human {

val age = 20

}

Kotlin Bytecode Viewer

The simplest tool that can be used to inspect how Kotlin code works under the hood is Kotlin Bytecode Viewer.

In Intellij IDEA go to Tools-> Kotlin -> Kotlin Bytecode Viewer. A window that is opened shows bytecode that is generated by the compiler.

Press the Decompile button and you will see that the decompiled to Java version of the Human class looks as follows:

public final class Human {

private final int age = 20;



public final int getAge() {

return this.age;

}

}

The snippet above shows that under the hood the age property contains the age field and the getAge getter. And we can access the age field from an outer scope only using the getter that is called under the hood.

Backing fields

Sometimes we want to provide a getter or setter with custom logic. In this case we should use the backing fields feature.

The snippet below demonstrates that we can access the field variable in a scope of a custom getter or setter:

class Human {

val age = 20

get() {

println("Age is: $field")

return field

}

}

The snippet above shows how to use this approach. We can’t just reffer to a property in getter or setter because it will lead to recursive invoking. The decompiled to Java version of this code looks as follows:

public final class Human {

private final int age = 20;



public final int getAge() {

String var1 = "Age is: " + this.age;

System.out.println(var1);

return this.age;

}

}

Backing properties

The backing fields feature allows us to access a field of a property only in a scope of getter and setter. But what if we encounter a case that is not covered by functionality of the backing fields feature and we want to access the field directly without usage of the getter or setter we should use the backing properties feature.

class Human {

private val _age: Int = 20

val age: Int

get() {

return _age

}



val printAge = {

println("Age is: $_age")

}

}

In the example above, we declare a field explicitly using underscore before variable name. The field has to also be marked with the private modifier. The decompiled to Java version of this code looks as follows:

public final class Human {

private final int _age = 20;

@NotNull

private final Function0 printAge = (Function0)(new Function0() {

public Object invoke() {

this.invoke();

return Unit.INSTANCE;

}



public final void invoke() {

String var1 = "Age is: " + Human.this._age;

System.out.println(var1);

}

});



public final int getAge() {

return this._age;

}



@NotNull

public final Function0 getPrintAge() {

return this.printAge;

}

}

The snippet above shows that the backing properties feature allows us to access fields directly even in the most sophisticated manner.

Further reading

You can get more details about how properties work under the hood and how to write Kotlin code with minimum overhead in the Mastering High Performance with Kotlin book.

Conclusions

Kotlin is an amazing language that allows us to write code in more concise and reliable way. But when we move from Java to Kotlin we should understand that these two languages support different concepts.

In this article we tocuhed concepts of properties and fileds and looked at examples how to work with properties with minimum overhead.

Thanks for reading!