Did you know that you can inline properties in Kotlin? I discovered this small feature accidentally while browsing through Kotlin docs, and thought it’s worth a short article. So why is this useful?

Let’s take a trivial Android example:

val View.isVisible
  get() = visibility == View.VISIBLE

That’s a simple yet convenient helper that hides the comparison operation behind a Boolean property, making your code look like this:

if (button.isVisible) {
  Toast.makeText(context, "I'm a button!", Toast.LENGTH_SHORT).show()
}

isVisible is actually an extension property, since it’s declared on an existing View class. Extension properties, similar to extension functions, are just syntactic sugar on top of good old Java static methods, with the first method parameter becoming the receiver in the extension function. If we decompile the previous snippet, using the “Show Kotlin Bytecode” feature (if you’re in Android Studio, open Tools -> Kotlin -> Show Kotlin Bytecode), we’ll see the following Java code:

if(ViewKt.isVisible((View)button)) {
  Toast.makeText(CheckNowView.this.getContext(), (CharSequence)"I'm a button!", 0).show();
}

As expected, the code invokes static isVisible() method in ViewKt class (the file with the extension property is called view.kt), passing button as the first argument. Let’s now mark our property’s getter with inline and see what it changes:

val View.isVisible
  inline get() = visibility == View.VISIBLE

Decompiled:

View $receiver$iv = (View)button;
if($receiver$iv.getVisibility() == 0) {
  Toast.makeText(CheckNowView.this.getContext(), (CharSequence)"I'm a button!", 0).show();
}

As you see, the comparison operation has been inlined on the call site, removing the static method invocation. This code looks almost as if you’d write it in Java, but the Kotlin counterpart looks a lot neater.

Declaring Inline Properties

Here are a few notes on the usage of inline properties: with vars, you can mark both the getter and the setter inline:

var View.someProperty: String
  inline get() = "Random value"
  inline set(value) {
    println("Value was set")
  }

If this is the case, you can actually mark the property itself inline, that will propagate the setting to both accessors:

inline var View.someProperty: String
  /* inline */ get() = "Random value"
  /* inline */ set(value) {
    println("Value was set")
  }

inline is forbidden on properties that have a backing field:

// won't compile!
var upperCaseString: String = ""
  inline get() = field.toUpperCase()

The rule also applies to the accessor that doesn’t reference the backing field:

// won't compile!
var upperCaseString: String = ""
  get() = field.toUpperCase()
  inline set(value) {
    println("Field set!")
  }

And last but not least, keep in mind that inlining will often increase the overall bytecode size, so avoid inlining accessors that contain big chunks of code:

// not the best idea!
var aProperty: String
  get() = ""
  inline set(value) {
    // a lot of code here!
  }

Conclusion

When used properly, inlining the properties can help the compiler produce more optimal bytecode, removing unnecessary indirections. The trivial example we looked at might give you an idea about which accessors are worth inlining. In any case, rely on the decompiler to see exactly what the Java counterpart of your code looks like.

Cheers!