Synthetic Accessors in Kotlin
Tags: kotlin, android, java
Published: 2017-07-10 14:03:12

---
title: Synthetic Accessors in Kotlin
published: true
description: Assessing some hidden costs in Kotlin
tags: Kotlin, Android, Java,
---

So this is a pretty nerdy blog and should be a quick one, but I just wanted to share my findings.

As you may know, [accessing private methods or fields in Java](https://medium.com/thoughts-overflow/effects-of-javas-synthetic-accessor-methods-in-android-bb67b3bac22e) from nested or anonymous inner classes results in the creation of [synthetic accessor methods](https://developer.android.com/training/articles/perf-tips.html#PackageInner). Jake Wharton’s [talk on Java’s hidden costs](http://jakewharton.com/exploring-java-hidden-costs/) is worth a watch here if you have no idea what I’m talking about.

These synthetic accessors are generated by the compiler and have big drawbacks on Android — potentially adding hundreds if not thousands of unnecessary methods across a project, each contributing to hitting the dex limit. Direct access to these methods or fields can also be up to 7 times faster than using a getter, which is nothing to sniff at.

Consequently at Blockchain we use the [Thunk](https://android.googlesource.com/platform/packages/apps/Launcher3/+/master/src/com/android/launcher3/util/Thunk.java) annotation to signal to developers that we’ve changed the scope of a field or method for the sake of avoiding synthetic accessor creation. There’s also a handy inspection built into Android Studio to highlight cases that you might have missed:

![I highly recommend enabling this particular inspection.](https://cdn-images-1.medium.com/max/1600/1*RZhTqGk5RSrDWEKdxANeSQ.png)

This is pretty well known. But is this an issue in the new hotness, Kotlin?

In short, yes.

Ultimately this shouldn’t be too surprising: Kotlin compiles down to the equivalent Java bytecode, so this is indeed a problem here too. I figured it would be but I wanted to check, so here’s what I found:

```java
class SyntheticAccessorTest {

    private var counter = 0

    fun main(args: Array<String>) {

        val someClass = SomeClass(object : SomeInterface {
            override fun doSomething() {
                printSomething()
            }

            override fun doSomethingElse() {
                counter++
            }
        })
    }

    private fun printSomething() {
        print("Something")
    }
}

class SomeClass(var listener: SomeInterface)

interface SomeInterface {

    fun doSomething()

    fun doSomethingElse()

}
```

Here we have a simple test class which invokes the constructor of another simple class and takes an anonymous implementation of an `interface`. In one of the callbacks, we invoke a function which is `private`, in another we increment a counter which is also `private`. Unfortunately because of this, the resulting `.class file` will absolutely have synthetic accessor methods, and once we look into it, it’s easy to see why.

In Android Studio, if we select `Kotlin Bytecode` and then `Decompile`, we get this Java (I’ve simplified this a bit for readability):

```java
public final class SyntheticAccessorTest {
   private int counter;

   public final void main(@NotNull String[] args) {
      new SomeClass(new SomeInterface() {
         public void doSomething() {
            SyntheticAccessorTest.this.printSomething();
         }

         public void doSomethingElse() {
            int var1;
            SyntheticAccessorTest.this.counter = (var1 = SyntheticAccessorTest.this.counter) + 1;
         }
      });
   }

   private final void printSomething() {
      String var1 = "Something";
      System.out.print(var1);
   }
}
```

If we then decompile the file with `javap -p -c SyntheticAccessorTest.class`, we then get this:

```java
public final class SyntheticAccessorTest {
  private int counter;
public final void main(java.lang.String[]);
    Code:
       [...]
private final void printSomething();
    Code:
       [...]
public SyntheticAccessorTest();
    Code:
       [...]
public static final void access$printSomething(SyntheticAccessorTest);
    Code:
       [...]
public static final int access$getCounter$p(SyntheticAccessorTest);
    Code:
       [...]
public static final void access$setCounter$p(SyntheticAccessorTest, int);
    Code:
       [...]
}
```

And there they are: it’s these `access$` methods that are the problem. In fact we get two for the `counter` field; one for `set`, one for `get`. You can easily see how this starts to add up quickly in an Android project.

If we change both `counter` and `printSomething()` to `internal`, we get this instead:

```java
public final class SyntheticAccessorTest {
  private int counter;
public final int getCounter$Test_Project();
    Code:
       [...]
public final void setCounter$Test_Project(int);
    Code:
       [...]
public final void main(java.lang.String[]);
    Code:
       [...]
public final void printSomething$Test_Project();
    Code:
       [...]
public SyntheticAccessorTest();
    Code:
       [...]
}
```

Better. But what is interesting here is that whilst we lose the synthetic accessor for `printSomething()`, we still get two methods for setting and getting the `counter` property. This is due to Kotlin automagically adding getters and setters to properties, and indeed if we check the generated Java, we see:

```java
public final int getCounter$production_sources_for_module_Test_Project() {
   return this.counter;
}

public final void setCounter$production_sources_for_module_Test_Project(int var1) {
   this.counter = var1;
}
```

Whether or not this seems unnecessary is up to you. In most Java classes you’d likely have written setters and getters anyway, so you haven’t really gained any unneeded methods in many situations. However in this case as the property is being accessed inside the parent class: these are obviously superfluous. Applying the same inspection to the equivalent Java code results in just 3 methods; two fewer than Kotlin.

If this is a huge concern for you there’s a simple fix; add the `@JvmField` annotation to the property and the getter/setter won’t be generated (thanks to Kirill Rakhman for the heads up).

So yes, you do need to be careful about accessing private functions in Kotlin for the same reason as you do in Java, and there appears to be a hidden cost in simply using properties. Sadly there isn’t yet an inspection for this yet, but I’m hoping that IntelliJ/Google will add this fairly soon. In the meantime, check your code carefully if the dex method count is something you worry about.