What is receiver in Kotlin? [duplicate] - kotlin

This question already has answers here:
What is a "receiver" in Kotlin?
(8 answers)
Closed 3 years ago.
someone to tell me what is the receiver in Kotlin? I checked the official documentation but I can't understand what it is.
Also you could tell me what function Int. has in the following code:
Int.(Int, Float) -> Int

In general, the receiver is this, the current instance.
In Kotlin, a lambda with receiver (which is what Int.(Int, Float) -> Int is) is a way to define functions which act similar to methods of their receiver: They can reference the receiver with this and can easily call other methods and properties of the receiver. (With the exception of private methods and properties.)
Here is some example code with the lambda type you gave, where the receiver is of type Int. The actual receiver instance is passed to invoke as its first argument.
val lambdaWithReceiver: Int.(Int, Float) -> Int = { firstArgument, secondArgument ->
println("this = $this") // accessing this
println("this.toLong() = ${toLong()}") // calling Int's methods
println("firstArgument = $firstArgument")
println("secondArgument = $secondArgument")
this + 3
}
// passes 7 as the receiver, 3 and 2F as the arguments
val result = lambdaWithReceiver.invoke(7, 3, 2F)
println("result = $result")
The above snippet will print the following output:
this = 7
this.toLong() = 7
firstArgument = 3
secondArgument = 2.0
result = 10

Related

Understanding a lambda construct that contains dot followed by brackets

This is the function declaration for rememberCoilPainter:
#Composable
fun rememberCoilPainter(
request: Any?,
imageLoader: ImageLoader = CoilPainterDefaults.defaultImageLoader(),
shouldRefetchOnSizeChange: ShouldRefetchOnSizeChange = ShouldRefetchOnSizeChange { _, _ -> false },
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)? = null,
fadeIn: Boolean = false,
fadeInDurationMs: Int = LoadPainterDefaults.FadeInTransitionDuration,
#DrawableRes previewPlaceholder: Int = 0,
): LoadPainter<Any> {
}
The line of code I am having difficulty understanding is:
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)? = null
A dot appears after Builder followed by (size: IntSize)
This is the first time I've seen this construct in Kotlin and am not sure how to interpret it. This is a lambda. Normally the dot after an object refers to a sub component of a class or a package. But the ( ) after the dot isn't clear.
How do I implement the requestBuilder parameter?
This is a function with receiver type as described here: https://kotlinlang.org/docs/lambdas.html#function-types
Function types can optionally have an additional receiver type, which is specified before a dot in the notation: the type A.(B) -> C represents functions that can be called on a receiver object of A with a parameter of B and return a value of C. Function literals with receiver are often used along with these types.
It could be tricky to understand at first, but this is like you are providing a function/lambda that is a method of ImageRequest.Builder. Or in other words: your lambda receives one additional parameter of type ImageRequest.Builder and it is available in the lambda as this.
You can provide requestBuilder as any other lambda, but note that inside it you will have access to properties and methods of ImageRequest.Builder object that was provided to you.
What you are looking at is a "function literal with receiver". Speaking generically, a type A.(B) -> C represents a function that can be called on a receiver object of A with a parameter of B and return a value of C. Or in your example:
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)?
We have a function requestBuilder which can be called on a ImageRequest.Builder with a parameter size: IntSize and returns another ImageRequest.Builder.
Calling this function is just like calling any other function with a lambda as a parameter. The difference: You have access to ImageRequest.Builder as this inside your lambda block.
Hope the following example helps understand lambdas with receiver type:
data class Person(val name: String)
fun getPrefixSafely(
prefixLength: Int,
person: Person?,
getPrefix: Person.(Int) -> String): String
{
if (person?.name?.length ?: 0 < prefixLength) return ""
return person?.getPrefix(prefixLength).orEmpty()
}
// Here is how getPrefixSafely can be called
getPrefixSafely(
prefixLength = 2,
person = Person("name"),
getPrefix = { x -> this.name.take(x) }
)
How do I implement the requestBuilder parameter?
Hope this part of the code snippet answers the above:
getPrefix = { x -> this.name.take(x) }
PS: These lambdas with receiver types are similar to extension functions IMO.

kotlin equality test of nullable reference of int [duplicate]

This question already has answers here:
Integers caching in Java [duplicate]
(2 answers)
Closed 2 years ago.
I do not understand this snippet of code I found on the official documentation:
fun main() {
val a: Int = 100
val boxedA: Int? = a
val anotherBoxedA: Int? = a
val b: Int = 100000
val boxedB: Int? = b
val anotherBoxedB: Int? = b
println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false
}
Why the equality changes when the variable's value change?
The JVM caches Integers for values between -128 and 127. Integers outside that range may or may not be cached - if they aren't, then each call to Integer i = 128 will return a new object.
Kotlin inherits this behaviour (an Int? in kotlin is an Integer in Java).
So, back to your example:
100 gets cached, hence boxedA and anotherBoxedA are the same object
but 100000 is not cached and 2 different instances of Integers are returned

Is there any function like ap2, ap3 in arrow-kt?

I saw scala code using cats in this post.
val a = Some(7)
val b = Some(9)
Applicative[Option].ap2(Some(add))(a,b)
And I tried migrating this code to kotlin and arrow like following.
Option.applicative()
.tupled(Some(7), Some(9))
.ap(Some(::add))
// works but dirty
fun add(tuple: Tuple2<Int, Int>): Int = tuple.a + tuple.b
// not work, compilation error
// fun add(a: Int, b: Int): Int = a + b
As you noticed, Tuple2 must be specified in the add function signature.
I searched the official document of arrow, but there is no apN function like ap2, ap3, ap4.
Is there any way to use the second function which not included Tuple2 type?
Once version 0.10 is available Arrow will have a .tupled() method on function types that handles this, so you will be able to write:
Option.applicative()
.tupled(Some(7), Some(9))
.ap(::add.tupled())
fun add(a: Int, b: Int) = a + b
for functions of up to 22 arguments.

Operator call corresponds to a dot-qualified call which is not allowed on a nullable receiver error [duplicate]

This question already has answers here:
Kotlin Map with non null values
(5 answers)
Closed 4 years ago.
This code doesn't compile:
val map = mutableMapOf<Int, Int>()
ar.forEach{
if(!map.containsKey(it)) {
map[it] = 1
} else {
map[it] = map[it] + 1
}
}
This is the compilation error:
Operator call corresponds to a dot-qualified call 'map[it].plus(1)'
which is not allowed on a nullable receiver 'map[it]'.
Since the mutableMap I created is not having nullable parameters, I am wondering why do I need to add not null checks later on? This code passes:
else map[it] = map[it]!! + 1
It's because map[it] might return null if there's no entry in the map corresponding to that key. Even though you checked by calling containsKey on the line before, that doesn't guarantee that when you call map[it] you'll get a value back, as another thread might update the map's contents in between those two calls.

What does "with" mean in Kotlin?

I've read the docs on it 3 times and I still have no idea what it does. Can someone ELI5 (Explain Like I'm Five) it please? Here's how I'm using it:
fun main(args: Array<String>) {
val UserModel = UserModel()
val app = Javalin.create().port(7000).start()
with (app) {
get("/users") {
context -> context.json(UserModel)
}
}
}
with is used to access an object's members and methods without having to refer to the object once per access. It is (mostly) for abbreviating your code. It is frequently used when constructing an object:
// Verbose way, 204 characters:
var thing = Thingummy()
thing.component1 = something()
thing.component2 = somethingElse()
thing.component3 = constantValue
thing.component4 = foo()
thing.component5 = bar()
parent.children.add(thing)
thing.refcount = 1
// Terse way, 182 characters:
var thing = Thingummy()
with(thing) {
component1 = something()
component2 = somethingElse()
component3 = constantValue
component4 = foo()
component5 = bar()
parent.children.add(this)
refcount = 1
}
The documentation says:
inline fun <T, R> with(receiver: T, block: T.() -> R): R (source)
Calls the specified function block with the given receiver as its receiver and returns its result.
The way I think of it is that it is calling a function (the block) where this in the scope of the block is the receiver.
Whatever the block returns is the return type.
Essentially calling a method where you provide the implicit this and can return any result from it.
Here is an example to demonstrate:
val rec = "hello"
val returnedValue: Int = with(rec) {
println("$this is ${length}")
lastIndexOf("l")
}
The rec in this case is the receiver of the function call - the this in the scope of the block. The $length and lastIndexOf are both called on the receiver.
The return value can be seen to be an Int because that is the last method call in the body - that is the generic type parameter R of the signature.
The definition of with:
inline fun <T, R> with(receiver: T, block: T.() -> R): R (source)
Actually it's implementation is straight forward: The block is executed on receiver, which works for any type:
receiver.block() //that's the body of `with`
The great thing to mention here, is the parameter type T.() -> R:
It's called function literal with receiver. It's actually a lambda that can access the receiver's members without any additional qualifiers.
In your example the context of with receiver app is accessed in that way.
Besides stdlib functions like with or apply, this functionality is what makes Kotlin great for writing Domain Specific Languages as it allows the creation of scopes within which you have access on certain functionalities.
val citizen2 = Citizen("Tom", 24, "Washington")
val age = with(citizen2) {
println("$name - $age $residence ")
age = this.age + age
residence = "Florida"
age+10 // returns 58
}
println("${citizen2.name} - ${citizen2.age} - $age - ${citizen2.residence} ")
data class Citizen(var name: String, var age: Int, var residence: String)
Output:
Tom - 24 Washington
Tom - 48 - 58 - Florida
Note that :
We can access age property of citizen(receiver object) with this.age or age
last line(age+10 in this example) in the lambda of with() returns.
With is used to apply several operations to an object or access object's methods e.g. in this example we are accessing String's capitalize() extension method
data class Person(val name:String)
fun main(){
val person = Person("john doe")
with(person) {
println(name.capitalize()) // output John Doe
}
}
Under the hood with is a higher-order function. Here we are saying with the Person name call capitalize ( ). We don’t actually need ‘this’ because it is implicit and can be removed