Vincent Tsen
Android Kotlin Weekly

Android Kotlin Weekly

Understand Fields and Properties in Kotlin

How Kotlin implicitly implements field, getter and setter function for you when you declare a property?

Vincent Tsen's photo
Vincent Tsen
·Jul 30, 2022·

3 min read

Understand Fields and Properties in Kotlin

Subscribe to my newsletter and never miss my upcoming articles

Table of contents

  • Implicit Field, Implicit Getter/Setter
  • Implicit Field, Explicit Getter/Setter
  • Explicit Field, Explicit Getter/Setter
  • Private Set or Backing Properties?
  • Misuse of private set
  • Conclusion

Properties and fields terminologies in Kotlin sometimes is a bit confusing because technically, Kotlin doesn't have Fields. You can't declare a field. Everything is Properties!

However, to avoid confusion, I prefer to define Fields and Properties separately based on the following:

  • Fields are private member variables of a class. Memory is allocated.
  • Properties are public or protected getter or setter functions which allow you to access to the private fields.

I like to define like this because it helps my understanding and it also makes things a lot easier to explain.

Implicit Field, Implicit Getter/Setter

Let's look at this example. name is a property.

class Person {
    var name = "Vincent"
}

When you declare a property like this, Kotlin implicitly creates field, getter and setter functions for you.

In Java decompiled code, it looks like this:

public final class Person {
   @NotNull
   private String name = "Vincent";

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.name = var1;
   }
}

As you can see, private String name is the field (member variable). getName() and setName() are the property getter and setter functions (also known as property accessors)

Implicit Field, Explicit Getter/Setter

Of course, you can also explicitly define the property getter and setter functions, which also generates a very similar decompiled Java code.

class Person {
    var name: String = "Vincent"
        get() { return field }
        set(value) { field = value }
}

field is implicitly created here, which is also called Backing Fields. Providing property accessors (i.e. get() and set()) to the property is called Backing Properties.

Explicit Field, Explicit Getter/Setter

You can explicitly define Field too. Basically everything is explicit now.

class Person {  
    private var _name:String = "Vincent"  
    var name: String  
        get() { return _name }  
        set(value) { _name = value }  
}

Instead of implicit field, _name is the explicit field here.

Private Set or Backing Properties?

Now, you want the property name to be read only outside the class. So you can restrict the property setter using private set.

For example:

class Person {  
    var name: String = "Vincent"  
        private set  
}

Or you can also use Backing Properties. Remove the set() and change the var to val.

class Person {  
    private var _name:String = "Vincent"  
    val name: String  
        get() { return _name }  
}

Both of the code generate the same decompile Java code as below. Please note, the setName() function removed.

public final class Person {  
   @NotNull  
   private String name = "Vincent";  

  @NotNull  
   public final String getName() {  
      return this.name;  
  }  
}

I personally prefer private set because it has less code.

Misuse of private set

But wait, not so fast. What if you convert the following backing property

class MainViewModel: ViewModel() {
    private val _state: MutableState<Int?> = mutableStateOf(null)
    val state: State<Int?> = _state
    /*...*/
}

to private set

class MainViewModel: ViewModel() {
    var state: MutableState<Int?> = mutableStateOf(null)
        private set
}

This is a very good example of misusing the private set. What it really means is you can't assign a new variable to state outside the MainViewModel class. The state variable itself is still mutable (which means you can modify its value).

The backing property above exposes only the read only State, changing it to private set defeats its original purpose. So, in this scenario, you don't use the private set. This applies to any mutable data.

Conclusion

I think it is important to understand the fields and properties concepts here.

When you declare a property, it doesn't allocate a new memory because it is merely a getter or setter function. However, if implicit field implementation is inferred (like code examples above), then yes, it takes up the memory allocation.

Finally, don't convert every backing property to private set. You shouldn't do that, especially your data is mutable.

Did you find this article valuable?

Support Vincent Tsen by becoming a sponsor. Any amount is appreciated!

See recent sponsors Learn more about Hashnode Sponsors
 
Share this