avatarVincent Tsen

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

4180

Abstract

  • delegated properties.</p><h1 id="3fd4">“by” Delegated Properties</h1><p id="9985">To implement the <code>by</code> operator, we need to implement the delegated class that has implemented <code>getValue()</code> and <code>setValue()</code> operator.</p><div id="ffa1"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">PropertyDelegate</span><<span class="hljs-type">T</span>>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> value: T? = <span class="hljs-literal">null</span>) {

    <span class="hljs-keyword">operator</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getValue</span><span class="hljs-params">(thisRef: <span class="hljs-type">Any</span>?, property: <span class="hljs-type">KProperty</span><*>)</span></span>: T? {
    println(<span class="hljs-string">"property get value: <span class="hljs-variable">$value</span>"</span>)
    <span class="hljs-keyword">return</span> value
    }

    <span class="hljs-keyword">operator</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setValue</span><span class="hljs-params">(thisRef: <span class="hljs-type">Any</span>?, property: <span class="hljs-type">KProperty</span><*>, value: <span class="hljs-type">T</span>?)</span></span> {
    println(<span class="hljs-string">"property set value from <span class="hljs-subst">{this.value}</span> to <span class="hljs-variable">value</span>"</span>)
    <span class="hljs-keyword">this</span>.value = value
    }
    }

<span class="hljs-keyword">class</span> <span class="hljs-title class_">PropertyDelegateExample</span> {
<span class="hljs-keyword">var</span> value: String? <span class="hljs-keyword">by</span> PropertyDelegate()
<span class="hljs-keyword">var</span> anotherValue: String? <span class="hljs-keyword">by</span> PropertyDelegate()
}

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
<span class="hljs-keyword">val</span> example2 = PropertyDelegateExample()
<span class="hljs-comment">// property set </span> example2.value = <span class="hljs-string">"example2"</span>
<span class="hljs-comment">// property get </span> println(example2.value)
}</pre></div><p id="8d49">Output:</p><div id="5c87"><pre>property <span class="hljs-built_in">set</span> value <span class="hljs-keyword">from</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">to</span> example2 property <span class="hljs-built_in">get</span> value: example2 example2</pre></div><p id="707f">This line — <code>var value: String? by PropertyDelegate()</code> basically means, "the property value is <b>provided by</b> <code>PropertyDelegate()</code> delegated class. <code>PropertyDelegate()</code> takes responsibility to set and get the <code>value</code> property.</p><p id="a8d5">Please also note that the <code>anotherValue</code> boilerplate code is now removed!</p><h1 id="681c">Common Usages of “by” Operator</h1><h2 id="af8f">by lazy</h2><p id="4e43">The most common usage of delegated property in my opinion is <a href="https://vtsen.hashnode.dev/complete-c-to-kotlin-syntax-comparisons#heading-by-lazy-delegated-properties">by lazy</a>. I personally prefer <code>val</code> over <code>var</code>. So I use <code>by lazy</code> a lot whenever is possible instead of using <code>lateinit var</code></p><div id="5160"><pre><span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> navController: NavController <span class="hljs-keyword">by</span> lazy { findNavController() }</pre></div><p id="4462"><code>lazy</code> is a delegated property that is responsible to set the <code>navController</code>. <code>lazy</code> takes in <a href="https://vtsen.hashnode.dev/complete-c-to-kotlin-syntax-comparisons#heading-lambda-methods-functions">lambda function</a> and that last line is the return value of <code>NavController</code>. Once <code>navController</code> is accessed, the value will be ca

Options

ched and <code>findNavContorller()</code> won't be called again in the subsequence accesses.</p><h2 id="24a5">by viewModels</h2><p id="6931"><code>by viewModels</code>is also another very common usage of delegated property used to create the <code>ViewModel</code>.</p><div id="f911"><pre><span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> viewModel <span class="hljs-keyword">by</span> viewModels<MainViewModel> { MainViewModelFactory(application) }</pre></div><p id="fb11"><code>by viewModels</code> is similar to, <code>by lazy</code> which is specific for <code>ViewModel</code> creation. It takes in lambda function and the last line is the return value of the implementation of <code>ViewModelProvider.Factory</code> interface. For more detailed usages, you can refer to my previous article <a href="https://vtsen.hashnode.dev/recommended-ways-to-create-viewmodel-or-androidviewmodel#heading-by-viewmodels-activityviewmodels">here</a>.</p><h2 id="8f44">by mutableStateOf</h2><p id="639a"><code>by mutableStateOf</code> is what I learned recently while working on Jetpack Compose project.</p><p id="8a99"><b>Method 1 </b><code>MutableState<T></code> (backing property)</p><p id="b120">In <code>ViewModel</code> class, instead of using <code>MutableState<T></code> directly,</p><div id="51f9"><pre><span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> _snackBarStringIdState: MutableState<<span class="hljs-built_in">Int</span>?> = mutableStateOf(<span class="hljs-literal">null</span>)
<span class="hljs-keyword">val</span> snackBarStringId
<span class="hljs-keyword">get</span>() = _snackBarStringIdState.value

<span class="hljs-comment">// setting the value in ViewModel class</span> _snackBarStringIdState.value = R.string.no_internet</pre></div><p id="57c1">we can use <code>by mutableStateOf</code></p><p id="ffd2"><b>Method 2 </b><code>by mutableStateOf</code> (private set)</p><div id="22ee"><pre><span class="hljs-keyword">var</span> snackBarStringId: Int? <span class="hljs-function"><span class="hljs-keyword">by</span> <span class="hljs-title">mutableStateOf</span>(<span class="hljs-params"><span class="hljs-literal">null</span></span>)
<span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>

<span class="hljs-comment">// setting the value in ViewModel class </span> snackBarStringId</span> = R.<span class="hljs-built_in">string</span>.no_internet</pre></div><p id="0c00" type="7">Both methods are similar. The only difference is setting the value, as you can code see in the example above.</p><h1 id="eea5">Conclusion</h1><p id="5f2c">There are other delegated properties such as observable and storing properties, and you can see the example <a href="https://kotlinlang.org/docs/delegated-properties.html">here</a>. Since I seldom use 2 of them, I do not mention them here. I will update the “Common Usages” section above when I find them useful one day.</p><p id="0687">There are also <a href="https://kotlinlang.org/docs/delegation.html#overriding-a-member-of-an-interface-implemented-by-delegation">class delegation</a> using <code>by</code> operator to delegate your class implementation to another object.</p><p id="8bc8">To see more info about it, read the following article:</p><div id="7f55" class="link-block"> <a href="https://vtsen.hashnode.dev/what-is-delegation-interface-in-kotlin"> <div> <div> <h2>What is Delegation Interface in Kotlin?</h2> <div><h3>You may be familiar with delegated properties in Kotlin, but have you heard of delegation interface? This is one of the…</h3></div> <div><p>vtsen.hashnode.dev</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*SqCF64atSE42x0W_)"></div> </div> </div> </a> </div><p id="17f1"><i>Originally published at <a href="https://vtsen.hashnode.dev/understand-by-delegated-properties-in-kotlin">https://vtsen.hashnode.dev</a>.</i></p></article></body>

Understand “by” Delegated Properties in Kotlin

Simple way to understand “by” operator (used for delegated properties) in Kotlin and the reasons to use it.

When I first learned Kotlin, the by operator is an alien to me. What the hell is that? In this article, I'm going to provide a simple example to show the reasons why we want to use this by operator.

Custom Property get() and set()

Let’s say I want to create a custom property get() and set() to print out something when the property value is read and set. I will do something like this.

class PropertyAccessExample {  
    var value: String? = null  
        get() {  
            println("property get value: $field")  
            return field  
        }  
        set(value: String?) {  
            println("property set value from $field to $value")  
            field = value  
        }  

    var anotherValue: String? = null  
        get() {  
            println("property get value: $field")  
            return field  
        }  
        set(value: String?) {  
            println("property set value from $field to $value")  
            field = value  
        }  
}

fun main() {
    val example1 = PropertyAccessExample()
    // property set
    example1.value = "example1"
    // property get
    println(example1.value)
}

Output:

property set value from null to example1
property get value: example1
example1

Please note that the field here is an implicit field. To learn more about Properties and Fields in Kotlin, refer to this article.

The problem of this is I need to implement this custom get() and set() for all the properties that I would like to monitor. For example, anotherValue above is the boilerplate code. To reduce the boilerplate code, we use by operator - delegated properties.

“by” Delegated Properties

To implement the by operator, we need to implement the delegated class that has implemented getValue() and setValue() operator.

class PropertyDelegate<T>(private var value: T? = null) {  

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {  
        println("property get value: $value")  
        return value  
  }  

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {  
        println("property set value from ${this.value} to $value")  
        this.value = value  
    }  
}

class PropertyDelegateExample {  
    var value: String? by PropertyDelegate()  
    var anotherValue: String? by PropertyDelegate()  
}

fun main() {    
    val example2 = PropertyDelegateExample()  
    // property set  
    example2.value = "example2"  
    // property get  
    println(example2.value)  
}

Output:

property set value from null to example2
property get value: example2
example2

This line — var value: String? by PropertyDelegate() basically means, "the property value is provided by PropertyDelegate() delegated class. PropertyDelegate() takes responsibility to set and get the value property.

Please also note that the anotherValue boilerplate code is now removed!

Common Usages of “by” Operator

by lazy

The most common usage of delegated property in my opinion is by lazy. I personally prefer val over var. So I use by lazy a lot whenever is possible instead of using lateinit var

private val navController: NavController by lazy {
    findNavController()
}

lazy is a delegated property that is responsible to set the navController. lazy takes in lambda function and that last line is the return value of NavController. Once navController is accessed, the value will be cached and findNavContorller() won't be called again in the subsequence accesses.

by viewModels

by viewModelsis also another very common usage of delegated property used to create the ViewModel.

private val viewModel by viewModels<MainViewModel> {
    MainViewModelFactory(application)
}

by viewModels is similar to, by lazy which is specific for ViewModel creation. It takes in lambda function and the last line is the return value of the implementation of ViewModelProvider.Factory interface. For more detailed usages, you can refer to my previous article here.

by mutableStateOf

by mutableStateOf is what I learned recently while working on Jetpack Compose project.

Method 1 MutableState<T> (backing property)

In ViewModel class, instead of using MutableState<T> directly,

private val _snackBarStringIdState: MutableState<Int?> =  mutableStateOf(null)  
val snackBarStringId  
  get() = _snackBarStringIdState.value

// setting the value in ViewModel class
_snackBarStringIdState.value = R.string.no_internet

we can use by mutableStateOf

Method 2 by mutableStateOf (private set)

var snackBarStringId: Int? by mutableStateOf(null)  
    private set

// setting the value in ViewModel class 
snackBarStringId = R.string.no_internet

Both methods are similar. The only difference is setting the value, as you can code see in the example above.

Conclusion

There are other delegated properties such as observable and storing properties, and you can see the example here. Since I seldom use 2 of them, I do not mention them here. I will update the “Common Usages” section above when I find them useful one day.

There are also class delegation using by operator to delegate your class implementation to another object.

To see more info about it, read the following article:

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

Kotlin
Kotlin Beginners
Kotlin Delegates
AndroidDev
Android App Development
Recommended from ReadMedium