I have a code that looks like the following:
infix fun <T> Option<T>.valueIs(value : T): Pair<() -> Boolean,Set<Node>> {
val function = {this.selectedValue == value}
val parents = setOf(this)
return Pair(function, parents)
}
My question is if Kotlin will always create an anonymous object in val function = {this.selectedValue == value} in the JVM every time that this extension function is called or if it has some sort of optimization to reuse it if this and value are the same.
Kotlin, like Java, can avoid creating a new object each time if your lambda doesn't access (also called "capture") variables declared outside it (including this); {this.selectedValue == value} captures this and value, so it doesn't.
You could imagine some cache mapping captured variables to lambda instances, so it's effectively
private val lambdas = mutableMapOf<Any, () -> Boolean>()
infix fun <T> Option<T>.valueIs(value : T): Pair<() -> Boolean,Set<Node>> {
val function = lambdas.getOrUpdate(Pair(this, value)) {this.selectedValue == value}
val parents = setOf(this)
return Pair(function, parents)
}
but:
it prevents lambdas from being garbage-collected just in case you'll call the method with the same this and value later (could be fixed by using WeakHashMap);
it's non-trivial overhead even neglecting that;
it requires any captured values to have well-behaved hashCode and equals. Ok, they should have them anyway, but just imagine problems from debugging this if they don't!
Kotlin has another very important way to avoid creating objects for lambdas: passing them as arguments to inline functions. Of course it isn't applicable when you want to put your lambda into a data structure (even one as simple as Pair) or just return it.
Decompiling the bytecode:
#NotNull
public static final Pair valueIs(#NotNull final Option $this$valueIs, final Object value) {
Intrinsics.checkParameterIsNotNull($this$valueIs, "$this$valueIs");
Function0 function = (Function0)(new Function0() {
// $FF: synthetic method
// $FF: bridge method
public Object invoke() {
return this.invoke();
}
public final boolean invoke() {
return Intrinsics.areEqual($this$valueIs.getSelectedValue(), value);
}
});
Set parents = SetsKt.setOf($this$valueIs);
return new Pair(function, parents);
}
As we can see, the lambda creates a new object Function0 every time this function is called.
So, every time this function is called. It seems that a new object will be created.
Related
Arrow-fx has a type Atomic which is similar to java AtomicRef but with an initial value, which means I don't need to check every time while accessing the atomic value whether it's null.
Here is a simple example
import arrow.fx.coroutines.*
suspend fun main() {
val count = Atomic(0)
(0 until 20_000).parTraverse {
count.update(Int::inc)
}
println(count.get())
}
Now I would like to create a class member variable with this type, but since it's only possible to initialize within a suspend function I would like to know the possibility here.
The easiest way is to make a "fake constructor" in the companion object.
public class Thingy private constructor(
val count: Atomic<Int>
) {
companion object {
suspend fun invoke() = Thingy(Atomic(0))
}
}
Now when you write Thingy(), you're actually calling the invoke function in Thingy.Companion. For that function there are no restrictions over suspending, so you can initialize Atomic as shown above.
I'm writing a Kotlin inline class to make Decimal4J more convenient without instantiating any objects. I'm worried that scope functions might create lambda objects, thereby making the whole thing pointless.
Consider the function compareTo in the following example.
/* imports and whatnot */
#JvmInline
value class Quantity(val basis: Long) {
companion object {
val scale: Int = 12
val metrics: ScaleMetrics = Scales.getScaleMetrics(scale)
val arithmetic: DecimalArithmetic = metrics.defaultArithmetic
}
operator fun compareTo(alt: Number): Int {
with(arithmetic) {
val normal = when (alt) {
is Double -> fromDouble(alt)
is Float -> fromFloat(alt)
is Long -> fromLong(alt)
is BigDecimal -> fromBigDecimal(alt)
is BigInteger -> fromBigInteger(alt)
else -> fromLong(alt.toLong())
}
return compare(basis, normal)
}
}
}
Does the with(arithmetic) scope create a lambda in the heap? The docs on kotlinlang.org consistently refer to the scoped code as a lambda expression. Is there any way to use scope functions without creating objects?
All of the built-in scoping functions, including with, are marked inline, which means the implementation gets planted directly in the code that's calling it. Once that happens, the lambda call can be optimized away.
To be more concrete, here's the implementation of with (with the Kotlin contracts stuff removed, since that's not relevant here)
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return receiver.block()
}
Extension methods are, and always have been, syntax sugar resolved at compile time, so this is effectively
public inline fun <T, R> with(receiver: T, block: (T) -> R): R {
return block(receiver) // (with `this` renamed by the compiler)
}
So when we call
operator fun compareTo(alt: Number): Int {
with (arithmetic) {
println("Hi :)")
println(foobar()) // Assuming foobar is a method on arithmetic
}
}
The inline will transform this into
operator fun compareTo(alt: Number): Int {
({
println("Hi :)")
println(it.foobar()) // Assuming foobar is a method on arithmetic
})(arithmetic)
}
And any optimizer worth its salt can see that this is a function that's immediately evaluated, so we should go ahead and do that now. What we end up with is
operator fun compareTo(alt: Number): Int {
println("Hi :)")
println(arithmetic.foobar()) // Assuming foobar is a method on arithmetic
}
which is what you would have written to begin with.
So, tl;dr, the compiler is smart enough to figure it out. You don't have to worry about it. It's one of the perks of working in a high-level language.
By the way, this isn't just abstract. I just compiled the above code on my own machine and then decompiled the JVM bytecode to see what it really did. It was quite a bit noisier (since the JVM, by necessity, has a lot of noise), but there was no lambda object allocated, and the function was just one straight shot that calls println twice.
In case you're interested, Kotlin takes this example function
fun compareTo(alt: Number): Unit {
return with(arithmetic) {
println("Hi :)")
println(foobar())
}
}
to this Java, after being decompiled,
public static final void compareTo-impl(long arg0, #NotNull Number alt) {
Intrinsics.checkNotNullParameter((Object)alt, (String)"alt");
long l = arithmetic;
boolean bl = false;
boolean bl2 = false;
long $this$compareTo_impl_u24lambda_u2d0 = l;
boolean bl3 = false;
String string = "Hi :)";
boolean bl4 = false;
System.out.println((Object)string);
int n = so_quant.foobar-impl($this$compareTo_impl_u24lambda_u2d0);
bl4 = false;
System.out.println(n);
}
Quite a bit noisier, but the idea is exactly the same. And all of those pointless local variables will be taken care of by a good JIT engine.
Just some additional info to help clear up the terminology that led to your confusion.
The word “lambda” is defined as a syntax for writing a function. The word does not describe a function itself, so the word lambda has nothing to do with whether a function object is being allocated or not.
In Kotlin, there are multiple different syntaxes you can choose from to define or refer to a function. Lambda is only one of these.
// lambda assigned to variable
val x: (String) -> Unit = {
println(it)
}
// anonymous function assigned to variable
val y: (String) -> Unit = fun(input: String) {
println(input)
}
// reference to existing named function assigned to variable
val z: (String) -> Unit = ::println
// lambda passed to higher order function
“Hello World”.let { println(it) }
// anonymous function passed to higher order function
“Hello World”.let(fun(input: Any) { println(input) })
// reference to existing named function passed to higher order function
“Hello World”.let(::println)
// existing functional reference passed to higher order function
“Hello World”.let(x)
There is actually no such thing as a lambda object that can be passed around. The object is a function that could have been defined using any of the above syntaxes. Once a functional reference exists, the syntax that was used to create it is irrelevant.
With inline higher order functions, as the standard library scope functions are, the compiler optimizes away the creation of the functional object altogether. Of the four higher order calls in my example above, the first three will compile to the same thing. The last is a bit different because the function x already exists so it will be x itself that is invoked in the inlined code. Its contents don’t get hoisted out and called directly in the inlined code.
The advantage of using lambda syntax for higher order inline function calls is that it enables you to use keywords for the outer scope (non-local returns), such as return, continue, or break.
I am learning Kotlin coming from Java, and I stumbled upon an unexpected behavior.
I noticed, that in my below code, I seem to accidentally declare a new lambda at a bad position instead of using the one I already have. How can I fix this?
I wrote these two declarations:
/**
* Dataclass used as an example.
*/
data class Meeple(var name: String, var color: String = "translucent")
/**
* Function to map from a List<T> to a new List of equal length,
* containing the ordered elements received by applying a Mapper's map
* function to every element of the input List.
*
* #param T Type of input List-elements
* #param O Type of output List-elements
* #param mapper The mapping function applied to every input element.
* #return The List of output elements received by applying the mapper on all
* input elements.
*/
fun <T, O> List<T>.map(mapper: (T) -> O?): List<O?> {
val target = ArrayList<O?>();
for (t in this) {
val mapped: O? = mapper.invoke(t)
target.add(mapped);
}
return target;
}
The data class is just a dummy example of a simple object. The List.map extension function is meant to map from the elements of the list to a new type and return a new List of that new type, almost like a Stream.map would in Java.
I then create some dummy Meeples and try to map them to their respective names:
fun main(args: Array<String>) {
val meeples = listOf(
Meeple("Jim", "#fff"),
Meeple("Cassidy"),
Meeple("David", "#f00")
)
var toFilter: String = "Cassidy"
val lambda: (Meeple) -> String? =
{ if (it.name == toFilter) null else it.name }
toFilter = "Jim"
for (name in meeples.map { lambda }) {
println(name ?: "[anonymous]") // This outputs "(Meeple) -> kotlin.String?" (x3 because of the loop)
}
}
I did this to check the behavior of the lambda, and whether it would later filter "Jim" or "Cassidy", my expectation being the later, as that was the state of toFilter at lambda initialization.
However I got an entirely different result. The invoke method, though described by IntelliJ as being (T) -> O? seems to yield the name of the lambda instead of the name of the Meeple.
It seems, that the call to meeples.map { lambda } does not bind the lambda as I expected, but creates a new lambda, that returns lambda and probably internally calls toString on that as well.
How would I actually invoke the real lambda method, instead of declaring a new one?
You already mentioned in the comments you figured out that you were passing a new lambda that returns your original lambda.
As for the toFilter value changing: The lambda function is like any other interface. As you have defined it, it captures the toFilter variable, so it will always use the current value of it when the lambda is executed. If you want to avoid capturing the variable, copy its current value into the lambda when you define the lambda. There are various ways to do this. One way is to copy it to a local variable first.
var toFilter: String = "Cassidy"
val constantToFilter = toFilter
val lambda: (Meeple) -> String? =
{ if (it.name == constantToFilter) null else it.name }
toFilter = "Jim"
Pretty much anything you can do with Stream in Java, you can do to an Iterable directly in Kotlin. The map function is already available, as mentioned in the comments.
Edit: Since you mentioned Java behavior in the comments.
Java can capture member variables, but local variables have to be marked final for the compiler to allow you to pass them to a lambda or interface. So in this sense they capture values only (unless you pass member variable). The equivalent to Java's final for a local variable in Kotlin is val.
Kotlin is more lenient than Java in this situation, and also allows you to pass a non-final local variable (var) to an interface or lambda, and it captures the variable in this case. This is what your original code is doing.
Even though you have found the issue as you mention in comments, I am adding this answer with some details to help any future readers.
So when you create lambda using
val lambda: (Meeple) -> String? = { if (it.name == toFilter) null else it.name }
This basically translates to
final Function1 lambda = (Function1)(new Function1() {
public Object invoke(Object var1) {
return this.invoke((Meeple)var1);
}
#Nullable
public final String invoke(#NotNull Meeple it) {
Intrinsics.checkNotNullParameter(it, "it");
return Intrinsics.areEqual(it.getName(), (String)toFilter.element) ? null : it.getName();
}
});
Now correct way to pass this to your map method would be as you have mentioned in comments
name in meeples.map(lambda)
but instead of (lambda) you wrote { lambda }, this is the trailing lambda convention
name in meeples.map { lambda }
// if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses:
// If the lambda is the only argument in that call, the parentheses can be omitted entirely
this creates a new lambda which returns the lambda we defined above, this line basically gets translated to following
HomeFragmentKt.map(meeples, (Function1)(new Function1() {
public Object invoke(Object var1) {
return this.invoke((Meeple)var1);
}
#Nullable
public final Function1 invoke(#NotNull Meeple it) {
Intrinsics.checkNotNullParameter(it, "it");
return lambda; // It simply returns the lambda you defined, and the code to filter never gets invoked
}
}))
I'd like to understand Kotlin extension functions more and am trying to implement an extension function for a List, to get the index of an element by passing the value of the position (if that makes sense).
What I have:
fun List<String>.getItemPositionByName(item: String): Int {
this.forEachIndexed { index, it ->
if (it == item)
return index
}
return 0
}
Although this works fine, I would need the same thing for Int too.
To my question, is there a way of combining this into one extension function instead of two seperate ones? I acknowledge that this isn't a lot of code and wouldn't hurt to be duplicated but out of interest and for future references.
I'm aware of this question Extension functions for generic classes in Kotlin where the response is - as I understand it at least - "doesn't quite work like this, but I don't really need it for type but "just" for String and Int.
Kotlin supports what C++ people would refer to as specialization to a certain degree. It works just fine for very basic types like you're using so what you're asking of is definitely possible.
We can declare the following declarations. Of course you could just duplicate the code and you'd be on your way.
public fun List<String>.getItemPositionByName(item: String) = ...
public fun List<Int>.getItemPositionByName(item: String) = ...
If you're not a fan of repeating the code, the idiomatic way would be to make use of file-private functions and simply delegating to the private function.
private fun <T> getItemImpl(list: List<T>, item: T): Int {
list.forEachIndexed { index, it ->
if (it == item)
return index
}
return -1
}
public fun List<String>.getItemPositionByName(item: String) = getItemImpl(this, item)
public fun List<Int>.getItemPositionByName(item: Int) = getItemImpl(this, item)
This limits the getItemImpl which is fully generic to the current file you're in while the Int and String specializations are publicly available anywhere else.
Attempting to call getItemPositionByName on any list which is not of type List<Int> or List<String> will fail with a type error.
Kotlin Playground Link: https://pl.kotl.in/NvIRXwmpU
And just in case you weren't aware, the method you're implementing already exists in the standard library (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index-of.html)
The Kotlin standard library already has a function that does this: indexOf().
val one = listOf("a", "b", "c").indexOf("b")
check(one == 1)
One option is to look at the implementation of that function.
There is also the first() function, which you could use if you wanted write your own generic version:
fun <T> List<T>.getItemPositionByName(item: T) = withIndex()
.first { (_, value) -> item == value }
.index
fun main(args: Array<String>) {
val one = listOf("a", "b", "c").getItemPositionByName("b")
check(one == 1)
}
Or, rewriting your original version to use generics:
fun <T> List<T>.getItemPositionByName(item: T): Int {
this.forEachIndexed { index, it ->
if (it == item)
return index
}
return 0
}
Let's say I have an object which helps me to deserialize other objects from storage:
val books: MutableList<Book> = deserializer.getBookList()
val persons: MutableList<Person> = deserializer.getPersonList()
The methods getBookList and getPersonList are extension functions I have written. Their logic is allmost the same so I thought I may can combine them into one method. My problem is the generic return type. The methods look like this:
fun DataInput.getBookList(): MutableList<Book> {
val list = mutableListOf<Book>()
val size = this.readInt()
for(i in 0 .. size) {
val item = Book()
item.readExternal(this)
list.add(item)
}
return list
}
Is there some Kotlin magic (maybe with inline functions) which I can use to detect the List type and generify this methods? I think the problem would be val item = T() which will not work for generic types, right? Or is this possible with inline functions?
You cannot call the constructor of a generic type, because the compiler can't guarantee that it has a constructor (the type could be from an interface). What you can do to get around this though, is to pass a "creator"-function as a parameter to your function. Like this:
fun <T> DataInput.getList(createT: () -> T): MutableList<T> {
val list = mutableListOf<T>()
val size = this.readInt()
for(i in 0 .. size) {
val item = createT()
/* Unless readExternal is an extension on Any, this function
* either needs to be passed as a parameter as well,
* or you need add an upper bound to your type parameter
* with <T : SomeInterfaceWithReadExternal>
*/
item.readExternal(this)
list.add(item)
}
return list
}
Now you can call the function like this:
val books: MutableList<Book> = deserializer.getList(::Book)
val persons: MutableList<Person> = deserializer.getList(::Person)
Note:
As marstran mentioned in a comment, this requires the class to have a zero-arg constructor to work, or it will throw an exception at runtime. The compiler will not warn you if the constructor doesn't exist, so if you pick this way, make sure you actually pass a class with a zero-arg constructor.
You can't initialize generic types, in Kotlin or Java. At least not in the "traditional" way. You can't do this:
val item = T()
In Java, you'd pass a Class<T> and get the constructor. Very basic example of that:
public <T> void x(Class<T> cls){
cls.getConstructor().newInstance(); // Obviously you'd do something with the return value, but this is just a dummy example
}
You could do the same in Kotlin, but Kotlin has a reified keyword that makes it slightly easier. This requires an inline function, which means you'd change your function to:
inline fun <reified T> DataInput.getBookList(): MutableList<T> { // Notice the `<reified T>`
val list = mutableListOf<T>() // Use T here
val size = this.readInt()
for(i in 0 .. size) {
// This is where the initialization happens; you get the constructor, and create a new instance.
// Also works with arguments, if you have any, but you used an empty one so I assume yours is empty
val item = T::class.java.getConstructor().newInstance()!!
item.readExternal(this) // However, this is tricky. See my notes below this code block
list.add(item)
}
return list
}
However, readExternal isn't present in Any, which will present problems. The only exception is if you have an extension function for either Any or a generic type with that name and input.
If it's specific to some classes, then you can't do it like this, unless you have a shared parent. For an instance:
class Book(){
fun readExternal(input: DataInput) { /*Foo bar */}
}
class Person(){
fun readExternal(input: DataInput) { /*Foo bar */}
}
Would not work. There's no shared parent except Any, and Any doesn't have readExternal. The method is manually defined in each of them.
You could create a shared parent, as an interface or abstract class (assuming there isn't one already), and use <reified T : TheSharedParent>, and you would have access to it.
You could of course use reflection, but it's slightly harder, and adds some exceptions you need to handle. I don't recommend doing this; I'd personally use a superclass.
inline fun <reified T> DataInput.getBookList(): MutableList<T> {
val list = mutableListOf<T>()
val size = this.readInt()
val method = try {
T::class.java.getMethod("readExternal", DataInput::class.java)
}catch(e: NoSuchMethodException){
throw RuntimeException()
}catch(e: SecurityException){
throw RuntimeException()// This could be done better; but error handling is up to you, so I'm just making a basic example
// The catch clauses are pretty self-explanatory; if something happens when trying to get the method itself,
// These two catch them
}
for(i in 0 .. size) {
val item: T = T::class.java.getConstructor().newInstance()!!
method.invoke(item, this)
list.add(item)
}
return list
}