Qualified ‘this’ in Kotlin


The only thing we learnt about this pointer in other languages is “this is an implicit pointer which points to the calling object”. As clear from the definition, it points to the object which calls the respective function or property.
Now the real problem arises when we have an inner class or anonymous interface implementation. We lose the reference of the outer class. Let me give you an example.
  
//java code
//extending Android View class


public class CustomView extends View {

public CustomView(Context context) {
super(context);

getViewTreeObserver()
.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout() {
//this.
//will not get the reference of
//CustomView here
}
});
}
}
In the above code, we extended the class from View class which has a property of class ViewTreeObserver. ViewTreeObserver class has two functions addOnGlobalLayoutListener and removeGlobalOnLayoutListener which takes OnGlobalLayoutListener Interface reference object.

Now when we implemented the anonymous object of OnGlobalLayoutListener for the same, we can’t get the reference of my CustomView class inside the overridden method. Now If we want to call any function of CustomView from inside the overridden method, we can’t.

To do the same we need to define another final variable and use it.
  
//java code
//extending Android View class


public class CustomView extends View {

public CustomView(Context context) {
super(context);

final CustomView view = this;

getViewTreeObserver()
.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout() {
view.doSomething();
}
});
}

private void doSomething(){

}
}
Now to make our life easy, Kotlin has something called qualified ‘this’.

Let me give you the equivalent code in Kotlin.
  
class CustomView : View {

constructor(context: Context) : super(context) {

viewTreeObserver
.addOnGlobalLayoutListener (
object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
this@CustomView.doSomething()
}
})
}

private fun doSomething() {
}
}

or if you want to use a lambda
  
class CustomView : View {

constructor(context: Context) : super(context) {

viewTreeObserver
.addOnGlobalLayoutListener {
this@CustomView.doSomething()
}
}

private fun doSomething() {
}
}
as you can see we can even reference the this pointer using @ followed by the scope of that this pointer.
Let's take some other example
  
class OuterClass {

inner class InnerClass{

fun Int.intExtensionFunction(){

val outerThis = this@OuterClass
val innerThis = this@InnerClass
val intExtThis = this@intExtensionFunction

val currentThis = this
// int receiver, which will be an int

val funLiteral = lambda@ fun String.() {
val funLiteralThis = this
// funLiteral's receiver which will be a string
}


val funLiteral2 = { string: String ->
val funLiteral2This = this
//since this lambada doesn't have any receiver,
//this will be an int (the extension fun reference)
}

}
}
}
We can use any reference inside the inner class or even inner function based on our use case.

Things to remember,

  • In a member of a Class, this refers to the current object of that class.
  • In an extension function or a function literal with the receiver, this denotes the receiver parameter that is passed on the left-hand side of a dot.
  • If this has no qualifiers, it refers to the innermost enclosing scope.
  • No need to define any final object to use any this reference.


Reference: Kotlin docs