I'm brand new to Kotlin, and OOP in general. I've ...
# getting-started
m
I'm brand new to Kotlin, and OOP in general. I've been reading books and taking introductory courses online. But there are some things I just can't understand currently. Right now I'm learning about "Scoping Functions" such as apply, with, let, run, etc. I am really struggling to understand these functions, maybe because I'm having trouble understanding what a "receiver" is, and what the difference between "it" and "this" is, and when to use one vs the other. Can somebody please explain "receivers" and the difference between "it" and "this"? I do have a basic understanding of extender functions. Thanks!!
m
run vs let Suppose you have a list and you want to perform some operations like adding and removing an element
Copy code
val list = ArrayList<String>()
list.run {
   // here receiver is this. You can think like you are in the ArrayList class itself so we can directly call add and remove methods 
   add("Hello")
   add("World")
   removeAt(0)
}

list.let {
   // here receiver is it. You can think this like you have just renamed list to it. We would need to call methods on it as we would have called on list
   it.add("Hello")
   it.add("World")
   it.removeAt(0)
}
run and let both returns the last line of block so in example below let would return 2
Copy code
val value = list.let {
   it.add("Hello")
   2
}
print(value) //would print 2
in terms of receiver apply is same as run and also is same as let The difference between apply and run OR also and let is that apply/also return the object on which they were called and run/let returns last line of the block
Copy code
val value = list.also {
   it.add("Hello")
   2
}
print(value) //would print list
In above example we used also on list so value will be assigned to list no matter what last line of block is Regarding when to use which operator you can have a look into this flowchart: https://medium.com/androiddevelopers/kotlin-standard-functions-cheat-sheet-27f032dd4326 I hope this helps you understand the scopes
👍🏽 1
👏🏼 2
m
Thanks for the information guys! However, I'm still struggling to comprehend these functions. It seems that every source that discusses these functions references "receivers", and I still don't understand what those are. I'm still wondering if anybody can explain to me what a receiver is. Also what is the difference between "it" and "this"?
j
The difference between it and this is pretty simple. "it" is short for iterator, it's the default name for the individual elements for any sort of looping function. e.g. you can map over a list my calling
l.map{it.value}
The it is just the default name. You can actually assign a name if you want.
this
comes from OOP. Within the context of an object, any method can refer to the instance on which the method was called by using
this
. It's also possible to reference internal fields of the instance, so if there was a local variable named foo and a field with the same name, you could assign the field value using
this.foo = foo
The biggest difference is that in cases where there is no name collision, everything on
this
can be accessed directly without a prefix of
this.
The "receiver" is the actual backing instance receiving the calls. When you use "it" it's always explicit, so it's a bit more verbose but avoids name collisions. The functions that use "this" allow you to use an concise, implicit style but you have to worry about naming conflicts in case both "this" and your local scope have functions or variables with the same name. There is actually a third type of receiver which can delegate calls to the containing scope, which you would use in nested closures to allow implicit calls against elements one more more levels up. It's commonly seen in groovy, so you might see it if you are still using the old Gradle build scripts (not the kts ones).
m
ok. so "this" is used within an object (an instance of a class) to refer to the instanced object itself? and it is helpful really in cases where variables have the same name, because "this" can be used to reference the variable of the base object? is that correct?
but "this" isn't mandatory to use because Kotlin can infer where the variable is held, unless the variables have the same name, right?
j
Yes, basically. That's the origin, just remember that Kotlin is doing some magic behind the scenes. It's not really grafting your closure into the class. I don't know the implementation - could possibly be doing something similar to extension function.
m
1. So, if "this" is really just used within class and object definitions to reference the instanced object, where/when is "it" used? I've seen that "it" is used in lambdas if there is only one parameter and just helps make code more concise, and you stated that "it" is used in looping functions. As you said that "it" is short for "iterator", would it be more accurate to say that "it" is used in Kotlin functions that iterate through a collection, rather than "looping functions"? Is "it" used any other way? 2. How can I better understand Kotlin's scoping functions (ie: run, apply, let) in the context of these definitions of "this" and "it"? 3. I still do not understand what a "receiver" is. What do you mean it "is the actual backing instance of receiving the calls"?
j
1. Used in lambdas as the default parameter. Thinking it's only used on collections is a simplification. There may not be a backing collection (e.g. you can have a iterator on something that is lazy - generated on the fly). Also it can be used in cases where there is only one element, or during a transformation - take a look at the fold function. 2. Each of the scoping functions only differs in the returned object and the receiver. So they will either return the original object (apply), or the return value of the last statement (let) or Unit (run).. So you take the return value you want and the receiver (one of either it or this) and you can identify which function to use. 3. When you call a method on an object, the receiver is what is left of the '.' Remember this can be implicit. It all comes from OOP terminology. Typically you would have a method inside a class calling a method on another class. The first class instance is the sender, the instance of the second class is the receiver and the method called is the message.