0

I was taking a look on the apply scope function in kotlin and i had some problem understanding the synta

public inline fun <T> T.apply(block: T.() -> Unit):

What i do not understand is the part inside the function, more specific

T.()

What does T.() mean

user1520812
  • 81
  • 1
  • 8

1 Answers1

3

A parameter that looks like this:

someParameter: Something -> SomethingElse

is a function type. Just like how you can pass in parameters like Strings or Ints, you can pass around functions too. The notation tells you what parameters the function takes, and what its return value is.

(String) -> Unit represents a function that has a single String parameter, and returns Unit (i.e. nothing). (Int, Int) -> Int represents a function that takes two Int parameters and returns a single Int. You can probably think of a few functions that match that!

Assuming you already know what an extension function is (since you said this parameter was the bit you were confused about), then T.() -> Unit just represents a function you call on a receiver of type T, which takes no parameters, and returns Unit. It basically means you can do this:

"hi I'm a String".apply({ println(this) })
// or more usually, moving the lambda outside of the parentheses:
"hi I'm a String".apply { println(this) }

The lambda's type is T.() -> Unit - because you're calling apply on a String, that means T in this case is String. So your lambda's receiver, this in its scope, is a String - and you can make use of that in the lambda. It's usually used to configure something, e.g.

val myThing = SomeObject().apply {
    setOption(true)
    addMessage("Hi")
}

instead of

val myThing = SomeObject()
myThing.setOption(true)
myThing.addMessage("Hi")

See how the object can be excluded in the apply since it's the receiver, and you don't need to explicitly say this?


There are a bunch of these scope functions, like apply, run, with that all do something different in terms of what they return. apply returns the original object, not the result of the lambda - see how the function T.() -> Unit returns Unit, meaning any value you express will be ignored by apply (which returns the original object you called it on). run on the other hand, returns the result of the lambda, which could be a different type.

There are also equivalents that take a parameter instead of a receiver - e.g. also is the parameter equivalent of apply:

fun <T> T.apply(block: T.() -> Unit): T
fun <T> T.also(block: (T) -> Unit): T

See how that works? Same deal, but if you use that with a String, it's accessible in the function as a parameter instead (named it by default for a single parameter). Which you use depends on what's appropriate for the situation, and whether you think a named parameter is more readable or not

cactustictacs
  • 17,935
  • 2
  • 14
  • 25