dave08
01/04/2022, 12:20 PM@JvmInline
value class MethodParams1<A1>(val value: Array<Any?>) {
operator fun component1() = value[0] as A1
var arg1: A1
get() = value[0] as A1
set(value) { this.value[0] = value }
}
Joffrey
01/04/2022, 12:27 PMMethodParams1
that will decide this, not the implementation. To check a particular piece of code, you can try to decompile it to Java with the IDE.
For instance, you can try with this code:
fun main() {
val params = MethodParams1<String>(arrayOf("bob", "fred"))
println(params.component1())
println(params.arg1)
}
Which is decompiled this way:
public final class ValueClassExampleKt {
public static final void main() {
Object[] params = MethodParams1.constructor-impl(new Object[]{"bob", "fred"});
Object var1 = MethodParams1.component1-impl(params);
System.out.println(var1);
var1 = MethodParams1.getArg1-impl(params);
System.out.println(var1);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
As you can see, the array is not boxed into a MethodParams1
instance.dave08
01/04/2022, 12:34 PMObject[] params = MethodParams1.constructor-impl(new Object[]{"bob", "fred"});
Object var1 = MethodParams1.component1-impl(params);
Object var1 = MethodParams1.component1-impl(params);
is the function (even though I'm really not doing much there...)Object[] params = MethodParams1.constructor-impl(new
@NotNull
public static Object[] constructor_impl/* $FF was: constructor-impl*/(@NotNull Object[] value) {
Intrinsics.checkNotNullParameter(value, "value");
return value;
}
@JvmInline
value class MethodParamsO<A1>(val value: Array<Any?>) {
inline operator fun component1() = value[0] as A1
var arg1: A1
inline get() = value[0] as A1
inline set(value) { this.value[0] = value }
}
fun process(paramsO: MethodParamsO<String>, block: (MethodParamsO<String>) -> Unit) {
block(paramsO)
}
fun main() {
val params = MethodParamsO<String>(arrayOf("this", 0))
process(params) { (foo) ->
println("process $foo")
}
println(params.arg1)
params.arg1 = "this2"
println(params.arg1)
}
public static final void process_IC3gMN4/* $FF was: process-IC3gMN4*/(@NotNull Object[] paramsO, @NotNull Function1 block) {
Intrinsics.checkNotNullParameter(paramsO, "paramsO");
Intrinsics.checkNotNullParameter(block, "block");
block.invoke(MethodParamsO.box-impl(paramsO));
}
public static final void main() {
Object[] params = MethodParamsO.constructor-impl(new Object[]{"this", 0});
process-IC3gMN4(params, (Function1)null.INSTANCE);
int $i$f$getArg1 = false;
Object var1 = params[0];
System.out.println(var1);
Object value$iv = "this2";
int $i$f$setArg1 = false;
params[0] = value$iv;
$i$f$getArg1 = false;
var1 = params[0];
System.out.println(var1);
}
public static final Object component1_impl/* $FF was: component1-impl*/(Object[] $this) {
int $i$f$component1 = 0;
return $this[0];
}
Is there any way to avoid that @Joffrey?Joffrey
01/04/2022, 1:01 PMMethodParams1.constructor-impl
That's not being boxed?
Doesn't box, but calls that method...Regarding
constructor-impl
, this is the body of the MethodParams1
constructor. This is what allows you to write initialization code in init
blocks in your value class. This is really not a concern at all for performance.
it seems like a new instance IS still being created but not used?Only one instance of the array is created, it's theObject[] params = MethodParams1.constructor-impl(new
arrayOf
function that creates the initial array, but the body of constructor-impl
does not return a new array, it returns the same array.Seems like this usage (with componentX decomposition) seems to get boxedThe reason for boxing in your snippet is not due to decomposition methods, it's because you're using
MethodParams0
as a generic type argument in Function1
(because you use it in block: (MethodParamsO<String>) -> Unit
.
Avoiding boxing is not easy. As a rule of thumb, boxing will happen each time you use the value class as "another type" - this means each time it's assigned to a variable of a parent type, or used in a generic type where a generic type parameter is expected (like in Function1.invoke(T)
)dave08
01/04/2022, 1:06 PMJoffrey
01/04/2022, 1:10 PMdave08
01/04/2022, 1:12 PMJoffrey
01/04/2022, 1:14 PMif anyways there's no way to do this with value classes without them getting boxedI don't see one, but maybe I'm missing something
dave08
01/04/2022, 1:24 PMephemient
01/04/2022, 4:51 PM