What's Kotlin Backing Field For?

AndroidKotlinKotlin Android-Extensions

Android Problem Overview


As a Java developer, the concept of a backing field is a bit foreign to me. Given:

class Sample {
    var counter = 0 // the initializer value is written directly to the backing field
    set(value) {
        if (value >= 0) field = value
    }
}

What's this backing field good for? Kotlin docs said: >Classes in Kotlin cannot have fields. However, sometimes it is necessary to have a backing field when using custom accessors.

Why? What's the difference with using the properties name itself inside the setter, eg.*

class Sample {        
    var counter = 0
    set(value) {
        if (value >= 0) this.counter = value // or just counter = value?
    }
}

Android Solutions


Solution 1 - Android

Because, say if you don't have field keyword, you won't be able to actually set/get the value in the get() or set(value). It enables you to access the backing field in the custom accessors.

This is the equivalent Java code of your sample:

class Sample {
    private int counter = 0;
    public void setCounter(int value) {
        if (value >= 0) setCounter(value);
    }
    public int getCounter() {
        return counter;
    }
}

Apparently this is not good, as the setter is just an infinte recursion into itself, never changing anything. Remember in kotlin whenever you write foo.bar = value it will be translated into a setter call instead of a PUTFIELD.


EDIT: Java has fields while Kotlin has properties, which is a rather higher level concept than fields.

There are two types of properties: one with a backing field, one without.

A property with a backing field will store the value in the form of a field. That field makes storing value in memory possible. An example of such property is the first and second properties of Pair. That property will change the in-memory representation of Pair.

A property without a backing field will have to store their value in other ways than directly storing it in memory. It must be computed from other properties, or, the object itself. An example of such property is the indices extension property of List, which is not backed by a field, but a computed result based on size property. So it won't change the in-memory representation of List (which it can't do at all because Java is statically typed).

Solution 2 - Android

Initially, I too had a tough time understanding this concept. So let me explain it to you with the help of an example.

Consider this Kotlin class

class DummyClass {
    var size = 0;
    var isEmpty
        get() = size == 0
        set(value) {
            size = size * 2
        }
}

Now when we look at the code, we can see that it has 2 properties i.e - size (with default accessors) and isEmpty(with custom accessors). But it has only 1 field i.e. size. To understand that it has only 1 field, let us see the Java equivalent of this class.

Go to Tools -> Kotlin -> Show Kotlin ByteCode in Android Studio. Click on Decompile.

   public final class DummyClass {
   private int size;

   public final int getSize() {
      return this.size;
   }

   public final void setSize(int var1) {
      this.size = var1;
   }

   public final boolean isEmpty() {
      return this.size == 0;
   }

   public final void setEmpty(boolean value) {
      this.size *= 2;
   }
}

Clearly we can see that the java class has only getter and setter functions for isEmpty, and there is no field declared for it. Similarly in Kotlin, there is no backing field for property isEmpty, since the property doesn't depend on that field at all. Thus no backing field.


Now let us remove the custom getter and setter of isEmpty property.

class DummyClass {
    var size = 0;
    var isEmpty = false
}

And the Java equivalent of the above class is

public final class DummyClass {
   private int size;
   private boolean isEmpty;

   public final int getSize() {
      return this.size;
   }

   public final void setSize(int var1) {
      this.size = var1;
   }

   public final boolean isEmpty() {
      return this.isEmpty;
   }

   public final void setEmpty(boolean var1) {
      this.isEmpty = var1;
   }
}

Here we see both the fields size and isEmpty. isEmpty is a backing field because the getter and setter for isEmpty property depend upon it.

Solution 3 - Android

Backing fields are good for running validation or triggering events on state change. Think of the times you've added code to a Java setter/getter. Backing fields would be useful in similar scenarios. You would use backing fields when you needed to control or have visibility over setters/getters.

When assigning the field with the field name itself, you're actually invoking the setter (i.e. set(value)). In the example you have, this.counter = value would recurse into set(value) until we overflow our stack. Using field bypasses the setter (or getter) code.

Solution 4 - Android

My understanding is using field identifier as a reference to the property's value in get or set, when you want to change or use the property's value in get or set.

For example:

class A{
    var a:Int=1
        get(){return field * 2}    // Similiar to Java: public int geta(){return this.a * 2}
        set(value) {field = value + 1}
}

Then:

var t = A()
println(t.a)    // OUTPUT: 2, equal to Java code: println(t.a * 2)
t.a = 2         // The real action is similar to Java code: t.a = t.a +1
println(t.a)    // OUTPUT: 6, equal to Java code: println(t.a * 2)

Solution 5 - Android

The terminology backing field is filled with mystery. The keyword used is field. The get/set methods, follows immediately next to the member variable that is about to be get or set through this door protective methods mechanism. The field keyword just refers to the member variable that is to be set or get. At present Kotlin, you cannot refer to the member variable directly inside the get or set protective door methods because it will unfortunately result to infinite recursion because it will re-invoke the get or set and thus leds the runtime down into the deep abyss.

In C# though, you can directly reference the member variable inside the getter/setter methods. I am citing this comparison to present the idea that this field keyword is how the present Kotlin is implementing it but I do hope it will be removed in later versions and allow us to directly reference the member variable directly without resulting to infinite recursion.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYudhistira AryaView Question on Stackoverflow
Solution 1 - Androidglee8eView Answer on Stackoverflow
Solution 2 - AndroidthedarkpassengerView Answer on Stackoverflow
Solution 3 - AndroidMark MuchaView Answer on Stackoverflow
Solution 4 - AndroidFreddieView Answer on Stackoverflow
Solution 5 - AndroideigenfieldView Answer on Stackoverflow