Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does a Kotlin function signature with T.() mean?

Tags:

kotlin

This is a standard Kotlin function (as far as I know)

inline fun<T> with(t: T, body: T.() -> Unit) { t.body() } 

But could anyone write in simple English what does exactly the signature mean? It's a generic function for T, with first argument "t" of type T and second, "body" of function type, accepting a function of ???? and returning nothing (Unit)

I see this notation Something.() -> Something is used pretty frequently, i.e. for Anko:

inline fun Activity.coordinatorLayout(init: CoordinatorLayout.() -> Unit) = ankoView({ CoordinatorLayout(it) },init) 

but I don't think it was explained anywhere what .() means...

like image 701
ssuukk Avatar asked Oct 17 '15 19:10

ssuukk


People also ask

What does T stand for in Kotlin?

T. () -> Unit is an extension function type with receiver. Besides ordinary functions, Kotlin supports extension functions. Such function differs from an ordinary one in that it has a receiver type specification. Here it's a generic T.

What is function signature in Kotlin?

A function signature is a unique identification of a function for the Kotlin compiler. The signature consists of a function name, its parameters, and the return type.

What is function reference in Kotlin?

A function reference is typically used to pass an expression or set of instructions from one part of your code to another. There are a few other ways to accomplish this in Kotlin.

What is function type in Kotlin?

There are two types of function literals in Kotlin: Lambda expression. Anonymous function.


Video Answer


1 Answers

T.() -> Unit is an extension function type with receiver.

Besides ordinary functions, Kotlin supports extension functions. Such function differs from an ordinary one in that it has a receiver type specification. Here it's a generic T. part.

The this keyword inside an extension function corresponds to the receiver object (the one that is passed before the dot), so you can call its methods directly (referring to this from parent scopes is still possible with qualifiers).


Function with is a standard one, yes. It's current code:

/**  * Calls the specified function [block] with the given [receiver] as its receiver and returns its result.  *  * For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#with).  */ public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block() 

So it's a generic function for T and R, with first argument "receiver" of type T and second, f of extension function type, which extends T, returning type R which in turn returned by the with.

For example, you can use it like this:

val threadInfoString = with (Thread.currentThread()) {     // isDaemon() & getPriority() are called with new property syntax for getters & setters     "${getName()}[isDaemon=$isDaemon,priority=$priority]" } 


See documentation for extension functions here:
kotlinlang.org/docs/reference/lambdas.html#extension-function-expressions
kotlinlang.org/docs/reference/scope-functions.html#with kotlinlang.org/docs/reference/extensions.html


Added:

So the only valid f would be any 0-argument function defined for T?

Not really. In Kotlin function types and extension function types are unified, so that they can be used interchangeably. For example, we can pass String::length where a function (String) -> Int is expected.

// map() expects `(String) -> Int` // argument has type `String.() -> Int` strings.map(String::length) 

Types like Thread.() -> String & (Thread) -> String are the same from the background side – receiver, in fact, is the first argument.

So any of the following functions is suitable for Thread.() -> String argument:

fun main(args: Array<String>) {     val f1 = fun Thread.(): String = name     val f2 = fun Thread.() = name     val f3: Thread.() -> String = { name }     val f4: (Thread) -> String = { it.name }     val f5 = { t: Thread -> t.name }     val f6: (Thread) -> String = Thread::getNameZ     val f7: Thread.() -> String = Thread::getNameZ     val f8 = Thread::getNameZ }  fun Thread.getNameZ() = name 

Or you can simply use function literal ({}) as in the example with threadInfoString, but it works only when the receiver type can be inferred from the context.

like image 59
Artyom Krivolapov Avatar answered Sep 21 '22 16:09

Artyom Krivolapov