Slackbot
02/06/2022, 10:37 AMThomas Broyer
02/06/2022, 11:09 AMvalue
is a Provider
then it can be (re)configured after the wiring, otherwise you're forced to write someProperty.set(provider { someExtension.value })
. And in case value
is actually computed by another task, you also get an implicit dependency on that task that you lose with provider {}
.
…for the very small gain of writing value = "foo"
rather than value.set("foo")
.Big Chungus
02/06/2022, 11:21 AMtasks.someTask { someProperty.set(someExtension._value) }
where _value is of type Property with internal visibilityBig Chungus
02/06/2022, 11:23 AMFleshgrinder
02/06/2022, 3:39 PM.set(...)
instead of = ...
.Big Chungus
02/06/2022, 5:16 PMFleshgrinder
02/06/2022, 5:18 PMgetValue
function and you have your answer.
operator fun getValue(thisRef: Any, property: KProperty<*>)
Notice the KProperty<*>
which originates from, well, reflection.Big Chungus
02/06/2022, 5:25 PMBig Chungus
02/06/2022, 5:25 PMAnderson Lameck
02/08/2022, 10:11 PMKPropery<*>
is one of the reflection primitives found in the stdlib and not the reflection.
That being said, the getValue
operator function does not rely on reflection at allBig Chungus
02/08/2022, 10:26 PMFleshgrinder
02/09/2022, 7:18 AMFleshgrinder
02/09/2022, 7:19 AMandis a reflection object of thethis::prop
type describing prop itself.KProperty
Big Chungus
02/09/2022, 8:02 AMpublic void sayHi(Predicate<String> filter) {}
public Boolean myPredicate(String value) {}
public static void main() {
sayHi(::myPredicate)
// VS
sayHi((value) -> true)
}
Thomas Broyer
02/09/2022, 8:17 AMbuild/classes/…
dir and possibly use javap
to find out)Fleshgrinder
02/09/2022, 9:48 AMKFunction
(or anything like that). What it generates also depends on what kotlinc
flags you have used. By default it generates a kotlin.jvm.functions.FunctionXXX
(where XXX
is the artity, so e.g. 0
for no args, 1
for one arg, up to 22
). However, you can pass -Xlambdas=indy
(JVM 8+) to use invocedynamic
instead. (There are also -Xsam-conversions=indy
and -Xstring-concat=indy
[JVM 9+].) This is the reason why it's important to use inline
whenever you take a lambda. If you do that the FunctionXXX
does not need to be created. However, something many people are often not looking out for is the the code that is going to be inlined should be minimal, or it disables the optimization functionalities of HotSpot.Fleshgrinder
02/09/2022, 9:51 AMpackage com.hellofresh
import java.util.function.Predicate
class C {
fun sayHi(filter: Predicate<String>) = Unit
fun myPredicate(value: String): Boolean = true
}
fun main() {
val c = C()
c.sayHi(c::myPredicate)
}
The Kotlin Bytecode viewer of IntelliJ gives:
// C.java
package com.hellofresh;
import java.util.function.Predicate;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 5, 1},
k = 1,
d1 = {"\u0000$\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000b\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u000e\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u0006J\u0014\u0010\u0007\u001a\u00020\b2\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00060\n¨\u0006\u000b"},
d2 = {"Lcom/hellofresh/C;", "", "()V", "myPredicate", "", "value", "", "sayHi", "", "filter", "Ljava/util/function/Predicate;", "kotlin-libs.logging.main"}
)
public final class C {
public final void sayHi(@NotNull Predicate filter) {
Intrinsics.checkNotNullParameter(filter, "filter");
}
public final boolean myPredicate(@NotNull String value) {
Intrinsics.checkNotNullParameter(value, "value");
return true;
}
}
// TestKt.java
package com.hellofresh;
import java.util.function.Predicate;
import kotlin.Metadata;
import kotlin.jvm.functions.Function1;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 5, 1},
k = 2,
d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
d2 = {"main", "", "kotlin-libs.logging.main"}
)
public final class TestKt {
public static final void main() {
C c = new C();
Function1 var1 = (Function1)(new Function1(c) {
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object var1) {
return this.invoke((String)var1);
}
public final boolean invoke(@NotNull String p1) {
Intrinsics.checkNotNullParameter(p1, "p1");
return ((C)this.receiver).myPredicate(p1);
}
});
c.sayHi((Predicate)(new Predicate(var1) {
// $FF: synthetic field
private final Function1 function;
{
this.function = var1;
}
// $FF: synthetic method
public final boolean test(Object t) {
Object var10000 = this.function.invoke(t);
Intrinsics.checkNotNullExpressionValue(var10000, "invoke(...)");
return (Boolean)var10000;
}
}));
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
As you can see, here it even creates two objects under the hood.Big Chungus
02/09/2022, 10:19 AMBig Chungus
02/09/2022, 10:20 AMFleshgrinder
02/09/2022, 10:31 AMinvokedynamic
. Kotlin does not because Kotlin has back comp down to 6.Fleshgrinder
02/09/2022, 10:31 AMBig Chungus
02/09/2022, 10:31 AM