I was playing around with Kotlin Recivers until i get stuck with this block of code
assume this varaible
var greet: String.() -> Unit = {
println("Hello $this")
}
String is the receiver
() -> Unit is the function type
And we can call it in that form , which is clear enough for me
"my extintion text".greet() //--> prints "Hello extintion text"
But
with this approch i can't get to understand the trick behind intializing the greet
variable as we havn't set any parameter and how Kotlin idintiy my
passed value ("my extintion text") as A string
and use greet exintion on it
greet("also my extintion text") //--- prints "Hello also extintion text"
Your lambda when decompiled, shows this:
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
And this is how the Main method looks like:
public final class MainKt {
public static final void main() {
Function1 greet = (Function1)null.INSTANCE; //Your 'greet' is of Function1 type which has 'invoke' method.
greet.invoke("my extintion text"); //Calling the 'invoke' method of Function1.
}
The compiler calls the invoke() method passing your "my extintion text" string and prints it
There is no trick, the compiler will eventually use the invoke() method pass in the parameters just like any regular method.
Based on #Tasser answer i can understand how it works now
but i would illustrate in diffrent manner so it might be more persuasive for some one
starting with the declaring A simple lamba experation
var greet: String.() -> Unit
when we defined our variable in such manner our variable as #Tasser briefed is now A Functional type that implements "Function1 interface" when decompiled
it has only one operator function public operator fun invoke(p1: P1): R
and here we came pivotal part operator fun i(p1: P1): R
this function invoked immediately caues it mathed with argument type
and because our experation {
println("Hello $this")
} is decombiled through implementing the "Function1 interface" with operator fun invoke(p1: P1): R , thats is why my implementaion get executed
Related
I'm having trouble understanding lambda.
In particular, things like T.() -> R in the run() is more confusing.
public inline fun <T, R> T.run(block: T.() -> R): R = return block()
Questions
fun main() {
test {
this.replace("3","B")
}
}
fun test(block: String.(Int) -> Unit) {
"TEST".block(7)
}
In this code, in the block parameter, String.() means to define block as an extension function of the String class? So block requires String value when calling?
and,
fun main() {
"A".test {
this.replace("3","B")
}
}
fun String.test(block: String.(Int) -> Unit) {
block(7)
}
When calling the block in this code, why don't we need the receiver type?
in the block parameter, String.() means to define block as an extension function of the String class? So block requires String value when calling?
Yes. The block is effectively an extension function on the String class: within the block, this is the relevant String instance.
When calling the block in this code, why don't we need the receiver type?
Because there's already an implicit receiver. test() is itself an extension function on String, so within the body of test(), this is a String. And so you can call any of the methods of String without needing to qualify them with this. — including extension methods such as block.
Consider a simpler case with ‘real’ methods instead of extension methods:
class C {
fun a() {
// …
}
fun b() {
a() // Implicit receiver
}
}
a() is a method of class C, and so it needs a instance of C. But b() doesn't need to specify an instance of C when calling a(), because it already has its own receiver.
It could have been written as this.a(), but there's no need, as this is always an implied receiver when you don't specify one. (Some people seem to like an explicit this., but to me it's just pointless visual noise…)
Although extension methods are implemented a little differently ‘under the covers’, the syntax works in exactly the same way. So the call to block() in your second example has an implicit this..
In particular, things like T.() -> R in the run() is more confusing.
public inline fun <T, R> T.run(block: T.() -> R): R = block()
Here T and R are of a generic type, which could be of any data type Int, String or a Class etc. You get the picture.
block: T.() -> R, it's saying that the block has to be an extension function of type T, that could return any type R and this R could be anything, Unit, String, Class etc.
A lambda returns the value of its last expression, so whatever expression is on the last line of your lambda it would return it, that is of type R.
Now when we use that run method on any object, it gives us the same object as the lambda receiver (this) inside the lambda, because our lambda is an extension function of the same type on which we've called this.
var a = 1
val b = a.run {
this + 6
"incremented"
}
On using run method on a, our generic T type becomes an Int and our object a is available inside the lambda as this, because, now it's an extension function of Int.
In lambda our last expression is "incremented" which is a String so here our R becomes a type of String. As the run method is returning this R, the value of variable b becomes incremented.
In this code, in the block parameter, String.() means to define block
as an extension function of the String class? So block requires String
value when calling?
If block is an extension function then you won't need to pass a String. When you call it on any String it would use that. But if block is not an extension function then you would've to pass it.
fun test(block: String.(Int) -> Unit) {
"TEST".block(7)
}
.
fun String.test(block: String.(Int) -> Unit) {
block(7)
}
When calling the block in this code, why don't we need the receiver type?
In latter, the test method is an extension function of String, which is available as this in the method body, and all of the functions of the String are also available, that you can use with or without this on the receiver object. As block is also an extension function of String it can be accessed directly.
Meanwhile, in the former, there is no receiver object of type String is available in the method body, which is why you've to explicitly call it on a String.
I need some help understanding the following code as I am complete Kotlin newbie. This is from a kotlin post I found online
typealias genericContext<T> = Demo<T>.() -> Unit
class Demo<T> {
infix fun doThis(block: genericContext<T>) = block()
fun say(obj: T) = println(obj.toString())
}
fun main(args: Array<String>)
{
val demo = Demo<String>()
demo doThis { say("generic alias") }
}
So I understand that because of the infix we can skip the usual method call syntax i.e. demo.doThis and do demo doThis.
But I don't understand the following:
typealias genericContext<T> = Demo<T>.() -> Unit
This seems to associate the string genericContext<T> with something that looks like a lambda but I don't get the .() part. That extends Demo with a function ()? I am confused on how this works. Could someone shed some light?
typealias genericContext<T> = Demo<T>.() -> Unit is a type alias. It is simply giving a new name to the type on the right hand side. This means that declaration of doThis in Demo is equivalent to this:
infix fun doThis(block: Demo<T>.() -> Unit) = block()
Now for the type Demo<T>.() -> Unit:
This is a function type. A function of this type takes a Demo as it's receiver argument, and returns Unit. It is therefore the type of all functions defined either in the Demo class or as an extension on the Demo class.
When you provide a lambda of this type (for example when you call the doThis function), then this will point to a Demo-object inside the lambda. For example:
someDemo.doThis {
/* "this" is an object of type `Demo`.
* In this case it's actually "someDemo", because the implementation of "doThis"
* calls "block" on the implicit "this".
*/
this.say("Hey!")
}
In an attempt to understand more about Kotlin and play around with it, I'm developing a sample Android app where I can try different things.
However, even after searching on the topic for a while, I haven't been able to find a proper answer for the following issue :
Let's declare a (dummy) extension function on View class :
fun View.isViewVisibility(v: Int): Boolean = visibility == v
Now how can I reference this function from somewhere else to later call invoke() on it?
val f: (Int) -> Boolean = View::isViewVisibility
Currently gives me :
Error:(57, 35) Type mismatch: inferred type is KFunction2 but (Int) -> Boolean was
expectedError:(57, 41) 'isViewVisibility' is a member and an extension
at the same time. References to such elements are not allowed
Is there any workaround?
Thanks !
Extensions are resolved statically, where the first parameter accepts an instance of the receiver type. isViewVisibility actually accept two parameters, View and Int. So, the correct type of it should be (View, Int) -> Boolean, like this:
val f: (View, Int) -> Boolean = View::isViewVisibility
The error message states:
'isViewVisibility' is a member and an extension at the same time. References to such elements are not allowed
It's saying that the method is both an extension function, which is what you're wanting it to be, and a member. You don't show the entire context of your definition, but it probably looks something like this:
// MyClass.kt
class MyClass {
fun String.coolStringExtension() = "Cool $this"
val bar = String::coolStringExtension
}
fun main() {
print(MyClass().bar("foo"))
}
Kotlin Playground
As you can see the coolStringExtension is defined as a member of MyClass. This is what the error is referring to. Kotlin doesn't allow you to refer to extension function that is also a member, hence the error.
You can resolve this by defining the extension function at the top level, rather than as a member. For example:
// MyClass.kt
class MyClass {
val bar = String::coolStringExtension
}
fun String.coolStringExtension() = "Cool $this"
fun main() {
print(MyClass().bar("foo"))
}
Kotlin Playground
A better fit is the extension function type View.(Int) -> Boolean:
val f: View.(Int) -> Boolean = View::isViewVisibility
But actually the extension types are mostly interchangeable (assignment-compatible) with normal function types with the receiver being the first parameter:
View.(Int) -> Boolean ↔ (View, Int) -> Boolean
I faced the same problem when I declared extension function inside another class and try to pass that extension function as parameter.
I found a workaround by passing function with same signature as extension which in turn delegates to actual extension function.
MyUtils.kt:
object MyUtils {
//extension to MyClass, signature: (Int)->Unit
fun MyClass.extend(val:Int) {
}
}
AnyClass.kt:
//importing extension from MyUtils
import MyUtils.extend
// Assume you want to pass your extension function as parameter
fun someMethodWithLambda(func: (Int)->Unit) {}
class AnyClass {
fun someMethod() {
//this line throws error
someMethodWithLambda(MyClass::extend) //member and extension at the same time
//workaround
val myClassInstance = MyClass()
// you pass a proxy lambda which will call your extension function
someMethodWithLambda { someIntegerValue ->
myClassInstance.extend(someIntegerValue)
}
}
}
As a workaround you can create a separate normal function and invoke it from an inline extension method:
inline fun View.isVisibility(v: Int): Boolean = isViewVisibility(this, v)
fun isViewVisibility(v: View, k: Int): Boolean = (v.visibility == k)
You can't call directly the extension method because you don't have the implicit this object available.
Using either a type with two parameters (the first for the implicit receiver, as #Bakawaii has already mentioned) or an extension type should both work without any warnings at all.
Let's take this function as an example:
fun String.foo(f: Int) = true
You can use assign this to a property that has a two parameter function type like this:
val prop: (String, Int) -> Boolean = String::foo
fun bar() {
prop("bar", 123)
}
Or, you can use an extension function type, that you can then call with either of these two syntaxes:
val prop2: String.(Int) -> Boolean = String::foo
fun bar2() {
prop2("bar2", 123)
"bar2".prop2(123)
}
Again, the above should all run without any errors or warnings.
I'm a beginner of Kotlin language and I want to understand everything in this programming language so.
1- what mean of the args: Array<String> in the parameter of the main function ?
2- why compilation error is shown when this line is removed ?
The main(Array<String>) function is an entry point of a program. The strings passed are the command-line arguments.
That is, when you run something like
$ java myprogram foo bar
the main function is called with ["foo", "bar"] as the argument.
This is very much the same thing that Java does, and Java emulates C in this regard.
I keep replacing it with vararg everywhere
object Application {
#JvmStatic
fun main(vararg args: String) {
Micronaut.build()
.packages("example")
.mainClass(Application::class.java)
.start()
}
}
fun main(args : Array<String>) {
println("Hello, world!")
}
In this example, a function named main is defined which returns Unit and takes an Array of strings as a parameter.
Depend on Java convention, this Kotlin code bellow's the same with Java code.
Kotlin code:
fun main(args : Array<String>) {
println("Hello, world!")
}
Java code:
public static void main(String[] args) {
println("Hello, world!");
}
According to #9000 "The main(Array) function is an entry point of a program. The strings passed are the command-line arguments." Each program must have the start entry point. That's just a convention to get the function call parameter.
In Kotlin I have this function to wrap a transaction:
fun wrapInTransaction(code: () -> Unit) {
realmInstance.beginTransaction();
code.invoke()
realmInstance.commitTransaction();
}
How can I get access to realmInstance in the invoked code?
The easy solution here is to make code a function with receiver:
fun wrapInTransaction(code: Realm.() -> Unit) {
realmInstance.beginTransaction();
realmInstance.code()
realmInstance.commitTransaction();
}
Inside a lambda which you pass as code you will be able to use this to reference the RealmInstance and to use its members directly as if inside a member function.
Calling realmInstance.code() is just calling code with passing realmInstance as a receiver to it.
The other answers correctly demonstrate how to pass the RealmInstance object to the lambda. In addition, you can make the whole function an extension function which makes the call site a bit prettier:
fun Realm.wrapInTransaction(code: Realm.() -> Unit) {
//this is implicit
beginTransaction();
code()
commitTransaction();
}
The call site will look like this:
Realm.getInstance(this).wrapInTransaction {
createObject(User.class)
}
Change the wrapInTransaction function to accept an extensions method on realmInstance like so:
fun wrapInTransaction(code:Realm.() -> Unit){
realmInstance.beginTransaction();
realmInstance.code()
realmInstance.commitTransaction();
}
Then you can use it like:
wrapInTransaction {
println("realm instance is $this, instanceId: $instanceId")
}
Where for the sake of the example the Realm looks like:
class Realm {
val instanceId = 42
fun beginTransaction() {
}
fun commitTransaction() {
}
}
The above technique is possible thanks to Kotlin's Function Literals with Receiver that make it possible to set the this instance (receiver) within lambda function body. It makes it easy to build type safe builders that reassemble ones from Groovy or Ruby.
This answer provides more samples on the technique.