How does high order 'run' function block work in Kotlin? - android

run signature looks like:
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
The way I see it, the callback (block), is being called via a receiver but without any parameters. So how someone (with a lot of credits here) , said me that:
1.
thing.run(::println)
is equivalent to :
2.
thing.run { println(this) }
I can't understant how the first is running at all... since the way i see it the println won't get any parameter

When you pass a function to a higher-order function by using the function reference syntax instead of a lambda, it doesn't matter if there's a receiver or not. The receiver is like any other parameter, and can be thought of as the first parameter.
So the syntax of run's function parameter:
T.() -> R
will be treated exactly the same as the syntax of let's function parameter:
(T) -> R
so ::println can match either of these.
This works in the other direction, too. When you pass an extension function or member function using function reference syntax, the receiver of the extension function is treated as the first parameter. Either of these is valid:
val list = listOf(1, 2, 3)
list.run(List<Int>::sum)
list.let(List<Int>::sum)
So whether there is a receiver or not only affects lambdas. The actual function signature is the same. You can see this issue if you try to define two functions like this. There will be a compiler error for the two functions having the same signature:
class Foo
fun bar(foo: Foo) {
println("Hello")
}
fun Foo.bar() {
println("Hello")
}

Related

can't understand about () -> Call<WeatherData>

suspend fun safeApiCall(
apiCall: () -> Call<WeatherData>
): Resource<WeatherData> {
apiCall.enqueue() //error Unresolved reference: enqueue
}
In the above code what it the meaning of () -> Call<WeatherData> and how it is different from Call<WeatherData>
Yeah the syntax is explained in the Function types section of #ADM 's link.
Basically apiCall's type is a function with no parameters (the (), like calling someFunction()) and it returns (->) a result with the type Call<WeatherData>. It's the equivalent of this:
fun apiCall(): Call<WeatherData>
except you can pass in any function that matches that signature (same parameter types, same return type). Which means you can pass in lambdas too
safeApiCall({
doStuff()
doMoreStuff()
doThingThatReturnsAWeatherDataCall()
})
(when the lambda is the only parameter it can be moved out of the parentheses, I just wanted to make it clear you're passing it in as a parameter)
If you do have a function declared somewhere that matches the signature, you can pass a reference to that in instead
fun coolWeatherFunction(): Call<WeatherData>
safeApiCall(this::coolWeatherFunction)
(you can drop the this, just showing how you refer to a function on a particular instance or class)
It can be more readable sometimes
"1 2 3 4 5".split(' ').map(String::toDouble).forEach(::println)
1.0
2.0
3.0
4.0
5.0

Kotlin: difference between IT and THIS keyword

In one of the kotlin interviews, someone asked me the difference between it & this keywords.
I have a search on google but unable to find a proper answer for the question.
Can someone guide me what's the actual difference between these two?
I know this is very basic question, I am a novice in the kotlin.
it is only relevant inside a lambda with a single parameter. It is the default name for a single parameter and is a shorthand that allows you to omit naming the single parameter. A function that is declared this way might look like this:
(String) -> Unit
In a lambda, this is the receiver argument. It only works if the function is defined as having a receiver, like this:
String.() -> Unit
If the function declaration does not have a receiver, this has the same meaning it does outside the scope of the lambda. For an extension function, that’s the receiver of the extension function. Otherwise, it’s the class containing the function.
You need to know about Scope Functions:
The Kotlin standard library contains several functions whose sole
purpose is to execute a block of code within the context of an object.
When you call such a function on an object with a lambda expression
provided, it forms a temporary scope.
Inside this scope there is a Context object either as this or it
In Scope functions run, apply and with the scope is (temporarily) changed to the scope of the object you are calling this function on:
val str = "Hello"
str.run {
//Here this refers to str
}
In Scope functions let, also the scope is not changed (remains the same as caller scope) but your lambda will receive the context as it inside the lambda:
val str = "Hello"
str.let {
//Here it refers to str
}
You can check the links for more information.
Difference between it & this keywords can be explained by taking example of lambda method receivers (a.k.a higher order functions).
Let's say you've written a function or using a function which provides you callback as lambda method receiver. Something like this: () -> Unit
So, there are two possibilities how you want your callback to be:
Providing parameter to callback
Parameter by callback means you want to give your callback a parameter that caller can use on the time of invocation, also considered as it.
Whatever written above simply means: (Int) -> Unit. this functional method parameter can give you integer at the time of invocation.
Check out the snippet below:
fun someMethodWithCallback(callback: (Int) -> Unit) {
callback(0)
}
// On the time of consumption, the `Int` parameter by default exposed to callback as it parameter.
obj.someMethodWithCallback { it -> // Here it is the method parameter of callback that we passed, you can also rename it to any other named value
// it can be directly used as Int value if needed or you can rename it at receiver above
}
Note: You can provide multiple parameters to callback and then you won't be able to receive it, rather callback would provide you number of variables passed instead.
Providing object to callback
Another way to provide callback is by providing object itself as callback parameter. Which means that callback syntax slightly changes and gives you object itself as callback parameter this.
Whatever written above simply means: Int.() -> Unit. this functional method object can give you integer at the time of invocation.
Check out the snippet below:
fun someMethodWithCallback(callback: Int.() -> Unit) {
callback(0)
}
// On the time of consumption, the `Int` parameter by default exposed to callback as it parameter.
obj.someMethodWithCallback { this // Here this is the method object of callback that we passed, you can not rename it to anything else
// it can be used as Int value by referencing as this
}
Hope it make sense!
If this helps some one :
With scope like : run, apply, with, to call the methods of the object, we can call them directly as it has scope of the object. In another words run-block has "this" scope.
private fun methodWithRun() {
val dummy = Dummy()
dummy.run {
this.dummyFun()
this.dummyVar = "10"
}
}
While scope like : let, also, to call the methods of the object, we can call them using the "it" as it has scope of the class win which this method is written.
private fun methodWithLet() {
val dummy = Dummy()
dummy.let {
it.dummyFun()
it.dummyVar = "10";
}
}
I would like to go extreme fundamental with no fancy words. it keyword When you have one parameter you can call using it
keyword and it works so good with HOF, for instance,
private fun itKeyword(itKeyword:(String) -> Unit) {
itKeyword("")
}
fun callItFun() {
itKeyword {//it:String // this is high light over here like this
}
But if you try to do something like this:
private fun itKeyword(itKeyword:(String, Int) -> Unit) {
itKeyword("", 1)
}
fun callItFun() {
itKeyword {yourName, age -> //yourName, age is define by user
}
}
see? there is no it keyword define over here by compiler but instead we have to pass two parameters when we defined HOF but if we keep this empty, compiler will give us error Hey pass something dude, i don't what variable you are talking about there are two variables passed over here.
That means, when you have only one parameter you can call it by using it keyword.
this keyword
there are two scope or variables/properties global and local scope, when you have defined some variable as a global scope and you wanna call it in multiple methods/functions and at some place you have to use same type of another variable with the same name at local scope, in that case we will be using this keyword and why is that so?
private lateinit var mContext: Context
fun thisKeyword(mContext: Context) {
this.mContext = mContext
}
but what if we don't use this keyword and keep it like this:
private lateinit var mContext: Context
fun thisKeyword(mContext: Context) {
mContext = mContext
}
Compiler would say, mah man what have you done, didn't ring a bell in my head JK, Compiler would say, Val cannot be reassigned, wait what? we didn't init it as a val but if we see at global scope we have init it as var but guess what? compile is right. In Kotlin when pass something into functions parameter they act as a Val by default which means without this compiler was using local scope variables not global scope but when we use this keyword we tell compiler, with keyword this property over here before = is global scope this.mContext and after = is local one so this is the reason we use this keyword to refrains from variable conflict. i hope this helps, thankYou().
If you take a look at kotlin scope functions doc:
https://kotlinlang.org/docs/scope-functions.html
Some of them have "this" in their scopes and others use "it".
The difference is the following:
this: When you use scope functions that use "this", f.i. apply {} it changes the context of function's scope to the context of an object on which this function was called, e.g.:
//Outer context in outer scope
val alice = Person("Alice").apply {
//Person object's context in function's inner scope
this.age = 20 //"this" refers to the object's context
city = "London" //you can skip writing "this" because you are in the context of object
}
it: When you use functions that use "it", f.i. also {} it DOES NOT change the context of function's scope, so it remains the same as the context where the function was called, e.g.:
//Outer context in outer scope
val alice = Person("Alice").also {
//Same outer context in function's inner scope
it.age = 20 //"it" refers to the object's reference holder e.g. alice
it.city = "London" //you can not skip writing "it" because you are in outer context
}
NOTE:
The context and the scope are 2 different things.
In both cases the scope is changed so that if you declare a local variable within that scope it will not be visible from outer scope, and in 1 case the context changes and in the other one it remains the same and hence the usage of "this" and "it".

How to use a Kotlin extension function on a class?

I have a pretty short question about an extension function that would help clear some of my code. Basically I have some transformations on the hashCode of a class name and I want an extension function to do the transformations.
Example:
Getting the name hashCode: StateA::class.java.name.hashCode() where StateA is a simple class.
I want to the extension function like:
fun Class<*>.transformName(): String {
var hashString = this.javaClass.name.hashCode()
//Do my stuff on that hashString
return hashString
}
But this doesn't seem to work. When I apply the extension function with StateA.transformName(), the function gives me an error with Unresolved Reference.
I tried various things like applying the function to StateA::class or having the hashString equal to this::class.java.name.hashCode() but nothing works. Any tips?
You can't really achieve the StateA.transformName() syntax, as StateA just on its own refers to the companion object inside that class. So to get that syntax, you'd need to have a companion object inside every class that you want to use this extension on.
What you can do in a very general way is get the KClass that describes your class first. This gives you an object (the KClass instance) that you can then call an extension on:
fun KClass<*>.transformName() {
val clazz: Class<*> = this.java
clazz.name.hashCode()
}
StateA::class.transformName()
Another approach, which is less verbose on the call site could be a generic function like this, where the reified keyword allows you to access the concrete class that was used as the generic type parameter inside the function:
inline fun <reified T> transformName() {
val clazz: Class<*> = T::class.java
clazz.name.hashCode()
}
transformName<StateA>()

Return type is 'Unit?', which is not a subtype of overridden

Today while programming I found some odd behaviour in Kotlin. I could easily go around it, but I wonder if there is some reason to it or if it is a bug in Kotlin.
I have the following interface of a delegate which delegates the showing of a dialog to the Activity.
interface ViewModelDelegate {
fun showWarningDialog(textResource: Int)
}
I want to implement it as following in the Activity. Since I know I can only do it with a context and the Activity.getContext() may return null, I wrap the code in context?.let
override fun showWarningDialog(textResource: Int) = context?.let {
//show dialog
}
However this gives me a compile error:
Return type of 'showWarningDialog' is not a subtype of the return type of the overridden member 'public abstract fun showWarningDialog(textResource: Int): Unit defined in com.some.class.path'
Which really confused me, because I don't want to return anything. So since let returns whatever the function inside returns, I was wondering if I could fix it by writing a version of let which does not return anything.
fun <T, R> T.myLet(block: (T) -> R) {
let(block)
}
However this did not remove the compiler error. I found then that the mouseover text over the error gives more information (would be nice if the compiler did). It says:
Return type is 'Unit?', which is not a subtype of overridden
Now that tells me more about the problem. Because the function context?let call may not happen, it could return null. Now there are multiple ways to go around this. I could add ?: Unit too the end of the function call or I could define showWarningDialog to return Unit? which will allow me to call it just fine in most cases. However none of these solutions are desireable. I will probably just make a normal method and call the let inside of that instead of delegating the call to it. Costs me another level of indentation and an extra vertical line:
override fun showWarningDialog(textResource: Int) {
context?.let {
//show dialog
}
}
My question is, is this behaviour intended? Why or when would this be useful that a function that returns Unit cannot be delegated to an optional function call. I am very confused by this behaviour.
Single expression function
fun foo() = <expression>
by language design is equivalent to
fun foo(): <ReturnType> {
return <expression>
}
And because Unit? is not a not a subtype of Unit, you can't return it in from a function, which returns Unit. In this sense Unit just another type in the type system, it's not something magical. So it works just as it's supposed to work with any other type.
Why or when would this be useful that a function that returns Unit cannot be delegated to an optional function call.
So basically the question is why language designers did not created a special handling to accept Unit? from a function declaring Unit as a return type. I can think about a few reasons:
It requires to create this special handling in the compiler. Special cases lead to bugs, break slim language design and complicate documentation.
As it had to be a special case, it would be not really clear and predictable for programmers. Currently it works in the same way for all types, no special treatments. It makes the language predictable, you don't need to check the documentation for every type to see if it's treated specially.
It also adds some additional safety, so to make you notice that your expression can actually skip the calculation.
So trying to summarize, I would say making this case work does not add much of value but can potentially bring some issues. That's probably why they did not add it to the language.
lets discuss this case when you have return type for example String
interface someInterface{
fun somFun():String
}
class someClass : someInterface {
var someString:String? = null
override fun somFun()=someString?.let {
//not working
it
}
override fun somFun()=someString?.let {
//working
it
}?:""
}
so what we see that when parents return type is String you cannot return Strin? it is jus kotlins nullSafety ,
what is different when you don't have return type ? lets change the code above a little
interface someInterface{
fun somFun():String
fun unitFun()
}
class someClass : someInterface {
var someString:String? = null
override fun unitFun() {
//if it is possible to return null in here
}
override fun somFun()=someString?.let {
val someresult = unitFun().toString() //you will get crash
it
}?:""
}
now we have another function without return type (unitFun Unit)
so if you can return Unit? in your subclass it will cause a crash when you want to use the result of method because it is defined asUnit and you dont need any null checks.
generally it means Unit is also type and you need to keep it null safe .

Kotlin lambda compiles against java API but not against my own function

Here is a simplified example. This syntax works :
Handler().post({Log.v(TAG, "test")})
However, if I define this function
private fun doWithRunnable(toRun:Runnable) {
// whatever
}
And call it like this
doWithRunnable({Log.v(TAG, "test")})
Then I get the following error:
Required: RunnableFound: () -> Int
Both signatures look quite the same to me... what's the big difference?
In your Java example, you're taking advantage of the Java-interop feature for SAM Conversions. Unfortunately, this does not currently work for Kotlin interfaces, as the designers have deemed it unnecessary (there is some discussion on this see here).
Instead, you'd want to do something like:
fun doWithRunnable(runnable: () -> Any) {
// call it as `runnable()`
}
You could also define a typealias for this if you wanted (which is as close Kotlin comes to SAM syntax):
typealias RunMe = () -> Any
fun doWithRunnable(runnable: RunMe) {
runnable()
}
Note that currently, typealiases have to be declared at the top level, they can't be declared inside a class or method.

Categories

Resources