DEV Community

Cover image for Understand Fields and Properties in Kotlin
Vincent Tsen
Vincent Tsen

Posted on • Edited on • Originally published at vtsen.hashnode.dev

Understand Fields and Properties in Kotlin

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

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"
}
Enter fullscreen mode Exit fullscreen mode

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;
   }
}
Enter fullscreen mode Exit fullscreen mode

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 }
}
Enter fullscreen mode Exit fullscreen mode

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 }  
}
Enter fullscreen mode Exit fullscreen mode

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  
}
Enter fullscreen mode Exit fullscreen mode

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 }  
}
Enter fullscreen mode Exit fullscreen mode

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;  
  }  
}
Enter fullscreen mode Exit fullscreen mode

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
    /*...*/
}
Enter fullscreen mode Exit fullscreen mode

to private set

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

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.


Originally published at https://vtsen.hashnode.dev.

Top comments (0)