Let's consider this code:
class Receiver
fun higherOrder(extensionBlock: Receiver.() -> Unit) {
Receiver().extensionBlock() // works
extensionBlock(Receiver()) // works
}
fun Receiver.extension() = Unit
fun f() {
Receiver().extension() // works
extension(Receiver()) // unresolved reference
}
In my mind extension's functional signature is Receiver.() -> Unit
, same as extensionBlock
parameter's; i.e. we can call higherOrder(Receiver::extension)
fine. If this is true, I don't understand why the normal function call syntax is not consistent between an extension function and a parameter of the same type. I'm actually happy that extension(Receiver())
is not allowed, so there's only one way to call extension functions. So I guess the main question is Why can I do extensionBlock(Receiver())
when extensionBlock
has an extension function signature?
The higher order function returns the result of operation invocation with the supplied arguments. Declares a function that matches the operation signature. Invokes the higher-order function passing in two integer values and the function argument ::sum . :: is the notation that references a function by name in Kotlin.
A function that accepts and/or returns another function is called a higher-order function. It's higher-order because instead of strings, numbers, or booleans, it goes higher to operate on functions.
In Kotlin, a function which can accept a function as parameter or can return a function is called Higher-Order function. Instead of Integer, String or Array as a parameter to function, we will pass anonymous function or lambdas. Frequently, lambdas are passed as parameter in Kotlin functions for the convenience.
A higher order function is a function that takes a function as an argument, or returns a function . Higher order function is in contrast to first order functions, which don't take a function as an argument or return a function as output.
Higher-order functions in Kotlin are the functions that return a function or take a function as an argument or both. In other words, in Kotlin, you can have a function that takes another function as a parameter, return a function as a result, or does both, and these functions are called higher-order functions.
Kotlin language has superb support for functional programming. Kotlin functions can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions. In Kotlin, a function which can accept a function as parameter or can return a function is called Higher-Order function.
This is a simple extension function that allows a List of Strings to be filtered Run the code in the Kotlin playground. Here’s the sophisticated version of this leveraging Extension Function Expressions! Run the code in the Kotlin playground. allow: T. () -> Boolean is used instead of allow: (T) -> Boolean (from the unsophisticated example).
When the return executes in the lambda, it returns from the function in which the lambda was called from (not just the lambda block itself). The return from the outer function is possible only if the function that takes the lambda as an argument is inlined. More information on when to inline extension functions in Kotlin in Action, Ch 8 .
Maybe looking at the byte code helps...
extensionBlock : Receiver.() -> Unit
is a Function1<Receiver, Unit>
. Under the hood both calls are basically similar to extensionBlock.invoke(Receiver())
... (you could have even written that one as well in your comparison...) ... so the compiler does the magic that both work... why isn't it doing that also in the extension variant?
Extension functions are just static functions that take the receiver as argument. Now a guess why it isn't supported the same way as with higher order functions, even though technically it could be possible. Having something as follows in place, should it be an extension function then too?
fun extension(r : Receiver) = Unit // to extend or not to...?
I think it should, if you want to support extension(Receiver())
for extension functions (and from the byte code there is no difference). For now you couldn't have both functions in place, as you would get a platform declaration clash then (which basically speaks in favor to why extension(Receiver())
should work with the extension function).
I wonder whether it would be more or less logic for the compiler to handle if it were this way... to be honest, I like that higher order functions and extension functions differ in that regard... For me an extension function or a function taking something as argument are two different sort of things... it would probably be more confusing if an extension function could be used in both ways, i.e. extension(Receiver())
and Receiver().extension()
... probably it would be more confusing if ~normal functions would also be available as extension functions...
A pity, but also logical, that this on the Java side works: <WrapperClass>.extension(new Receiver())
(but we have no real extension there, so it's ok ;-))
These examples are two different things: First one is a function type with receiver A.() -> B
, second one is an extension function.
TL;DR: A.() -> B
is different way to write (A) -> B
. It does not extend anything.
Non-literal values of function types with and without receiver are interchangeable, so that the receiver can stand in for the first parameter, and vice versa. For instance, a value of type (A, B) -> C can be passed or assigned where a A.(B) -> C is expected and the other way around:
val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
val twoParameters: (String, Int) -> String = repeatFun // OK
Kontlin doc
In your case, the code applied to the explanation would look like:
val typeFunWithReceiver = Receiver.() -> Unit
val typeFunWithParam : (Receiver) -> Unit = typeFunWithReceiver // It does NOT extend Receiver
It is indeed confusing also to me now you're mentioning it. Even in the kotlin doc they refer to the resemblance:
This behavior is similar to extension functions, which also allow you to access the members of the receiver object inside the body of the function.
Source
TL;DR: A.funName() -> B
extends the A
class by the function funName()
. It is not a method type like before.
Kotlin provides the ability to extend a class with new functionality without having to inherit from the class or use design patterns such as Decorator.
Source
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With