Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 197 additions & 23 deletions docs/topics/this-expressions.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,216 @@
[//]: # (title: This expressions)

To denote the current _receiver_, you use `this` expressions:
The `this` expression refers to the current receiver. How you use `this` depends on the context:

* In a member of a [class](classes.md#inheritance), `this` refers to the current object of that class.
* In an [extension function](extensions.md) or a [function literal with receiver](lambdas.md#function-literals-with-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_. To refer to `this` in other scopes, _label qualifiers_ are used:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually very important: this doesn't only refer to the current receiver. It actually can refer to any of the nested receivers. For example, if I have

class Foo {
  fun foo() { }
}

class Bar {
  fun bar() { }

  fun Foo.moo() {
    this.bar()  // 'this' refers to the enclosing 'Bar' instance
    this.foo()  // 'this' refers to the extension receiver
  }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to the Qualified this section. Do you think it also makes sense to include the example like the one you've provided?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think this is incorrect. You write "If this has no qualifier, it refers to the receiver of the innermost enclosing scope", but my example above shows that this may refer to different enclosing scopes, even if it appears unqualified.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it now, thank you! What do you think about smth like this:

Kotlin code can have several receivers available at the same time. This happens when receiver scopes are nested. For example, an extension function declared inside a class can access members of both the extension receiver and the enclosing class object.
Kotlin can use these receivers implicitly when you access their members. Unqualified this refers to the receiver with the highest priority in the current scope. To refer to another receiver explicitly, use a qualified this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with your comment is in the "Unqualified this refers to the receiver with the highest priority in the current scope." part, unqualified this may refer to any receiver in scope, the closest one is just given more priority. So if, for example, several receivers have the same type, using the qualified this is the only possibility to access the outer one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah in that case my wording is too restrictive ig, so is the following would be correct:

Your code can have several receivers available at the same time when receiver scopes are nested. Kotlin can use any available receiver to access its members implicitly, but receivers from inner scopes have higher priority. To explicitly refer to a particular receiver, use a qualified this. This is especially useful when multiple receivers have members with the same name and you need to access a member of an outer receiver.

For example, in the following code, `this.name` means the `name` property of the current `Language` object:

## Qualified this
```kotlin
//sampleStart
class Language(val name: String) {
fun printName() {
println(this.name)
}
}

To access `this` from an outer scope (a [class](classes.md), [extension function](extensions.md),
or labeled [function literal with receiver](lambdas.md#function-literals-with-receiver)) you write `this@label`,
where `@label` is a [label](returns.md) on the scope `this` is meant to be from:
fun main() {
val language = Language("Kotlin")
language.printName()
// Kotlin
}
//sampleEnd
```
{kotlin-runnable="true"}

* In an [extension function](extensions.md) or a [function literal with receiver](lambdas.md#function-literals-with-receiver),
`this` refers to the receiver.

In the following example, we call `lastCharacter()`on the string
`"Kotlin"`. Therefore, `"Kotlin"` is the receiver. Inside the extension function, `this` refers
to `"Kotlin"`. This means that `this.length` is the length of `"Kotlin"`:

```kotlin
//sampleStart
fun String.lastCharacter(): Char {
println(this.length)
// 6
return this[this.length - 1]
}

fun main() {
println("Kotlin".lastCharacter())
// n
}
//sampleEnd
```
{kotlin-runnable="true"}

> In simple cases, you don't need to write `this` explicitly. Kotlin interprets it from the current scope.
> Learn more about [](#implicit-this).
>
{style="tip"}

## Qualified this

Your code can have several possible `this` values at the same time when receiver scopes are nested. For example, an inner
class can access both its own object and the outer class object. If `this` has no qualifier, it refers to the receiver
of the _innermost enclosing scope_. To refer to a receiver from an outer scope, use a qualified `this`.

To use a qualified `this`, add a [label](returns.md) qualifier:

```kotlin
class A { // implicit label @A
inner class B { // implicit label @B
fun Int.foo() { // implicit label @foo
val a = this@A // A's this
val b = this@B // B's this
this@label
```

val c = this // foo()'s receiver, an Int
val c1 = this@foo // foo()'s receiver, an Int
The label tells the compiler which receiver to access. You can use the name of an enclosing class or extension function.
For example, `this@foo` refers to the receiver of an enclosing extension function named `foo`.

val funLit = lambda@ fun String.() {
val d = this // funLit's receiver, a String
}
### Access an outer class from an inner class

val funLit2 = { s: String ->
// foo()'s receiver, since enclosing lambda expression
// doesn't have any receiver
val d1 = this
}
In an [inner class](nested-classes.md#inner-classes), plain `this` refers to the inner class instance. To access the outer class object,
use qualified `this`:

```kotlin
//sampleStart
class User(val name: String) {
inner class Age(val value: Int) {
fun printInfo() {

// Refers to the value property of the current Age object
println(this.value)
// 22

// Refers to the name property of the outer User object
println(this@User.name)
// Jane Doe
}
}
}

fun main() {
val user = User("Jane Doe")
val age = user.Age(22)
age.printInfo()
}
//sampleEnd
```
{kotlin-runnable="true"}

> Only inner classes hold a reference to an outer class instance. Regular [nested classes](nested-classes.md) don't have access to
> `this` from the outer class.
>
{style="note"}

### Access a class from an extension function

If you declare an extension function inside a class, two receivers are available:

* The extension receiver: the value on which you call the extension function.
* The dispatch receiver: the current object of the class where you declare the extension function.

Use qualified `this` to specify which receiver you need:

```kotlin
//sampleStart
class User {
val prefix = "Name"

fun String.formatName(): String {
return "${this@User.prefix}: ${this.uppercase()}"
}

fun printUser() {
println("Jane Doe".formatName())
}
}

fun main() {
val user = User()
user.printUser()
// Name: JANE DOE
}
//sampleEnd
```
{kotlin-runnable="true"}

Here:

* `this` refers to the extension receiver (the `"Jane Doe"` string).
* `this@User` refers to the current `User` object.
* `this@User.prefix` accesses the prefix property of the current `User` object.

### Access from a lambda

Unlike a regular lambda, a [lambda with receiver](lambdas.md#function-literals-with-receiver) has its own receiver. Therefore, `this` inside it
refers to that receiver. If a lambda with receiver is nested inside another receiver scope, add a label to the lambda
and use qualified `this` to specify which receiver you need:

```kotlin
//sampleStart
class User(val name: String) {
fun printWithPrefix() {
val print: String.() -> Unit = stringLabel@ {
println("${this@stringLabel}: ${this@User.name}")
}

print("User")
}
}

fun main() {
val user = User("Jane Doe")
user.printWithPrefix()
// User: Jane Doe
}
//sampleEnd
```
{kotlin-runnable="true"}

Here:

* `stringLabel@` labels the lambda.
* `this@stringLabel` refers to the string receiver of the lambda.
* `this@User` refers to the current `User` object.

The label doesn't call anything or change how the lambda works. It only helps you refer to the lambda's receiver.

### Access an anonymous object

Since anonymous objects don't have class names, you can't use a name like `this@YourClassName` to refer
to it. Inside an anonymous object, use plain `this` to refer to the object:

```kotlin
//sampleStart
interface UserPrinter {
fun print()
}

fun printUser(printer: UserPrinter) {
printer.print()
}

fun main() {
val printer = object : UserPrinter {
val name = "Jane Doe"

override fun print() {
// Refers to the name property of the anonymous object
println(this.name)
}
}
printUser(printer)
// Jane Doe
}
//sampleEnd
```
{kotlin-runnable="true"}

> If you create an anonymous object inside another class, you can use qualified `this` to access the outer class object.
> Use it to access an outer receiver, not the anonymous object itself.
>
{style="tip"}


## Implicit this

Expand Down
Loading