Berkeli Alashov
05/27/2022, 4:35 AM@Composable operator fun invoke
with interfaces - default arguments doesn't work. Is this a bug? Example in threadBerkeli Alashov
05/27/2022, 4:35 AMinterface A {
object B : A
operator fun invoke(truth: Boolean = true, data: String = "Data") {
assert(truth)
assert(data == "Data")
}
}
interface C {
object D : C
@Composable
operator fun invoke(truth: Boolean = true, data: String = "Data") {
assert(truth)
assert(data == "Data")
}
}
@Preview
@Composable
fun Test() {
// doesn't crash
A.B.invoke()
// doesn't crash
A.B()
// doesn't crash
C.D.invoke()
// crashes with assertion error
C.D()
}
Zach Klippenstein (he/him) [MOD]
05/27/2022, 4:38 AMBerkeli Alashov
05/27/2022, 4:39 AMtruth
is false, data
is nullZach Klippenstein (he/him) [MOD]
05/27/2022, 4:43 AMBerkeli Alashov
05/27/2022, 4:44 AMZach Klippenstein (he/him) [MOD]
05/27/2022, 4:45 AMBerkeli Alashov
05/27/2022, 4:46 AM@Composable
Zach Klippenstein (he/him) [MOD]
05/27/2022, 4:46 AMZach Klippenstein (he/him) [MOD]
05/27/2022, 4:47 AMZoltan Demant
05/27/2022, 5:10 AMBerkeli Alashov
05/27/2022, 5:12 AMLINENUMBER 382 L0
GETSTATIC app/A$B.INSTANCE : Lapp/A$B;
CHECKCAST app/A
ICONST_0
ACONST_NULL
ICONST_3
ACONST_NULL
INVOKESTATIC app/A$DefaultImpls.invoke$default (Lapp/A;ZLjava/lang/String;ILjava/lang/Object;)V
L1
LINENUMBER 384 L1
GETSTATIC app/A$B.INSTANCE : Lapp/A$B;
CHECKCAST app/A
ICONST_0
ACONST_NULL
ICONST_3
ACONST_NULL
INVOKESTATIC app/A$DefaultImpls.invoke$default (Lapp/A;ZLjava/lang/String;ILjava/lang/Object;)V
L2
LINENUMBER 387 L2
GETSTATIC app/C$D.INSTANCE : Lapp/C$D;
CHECKCAST app/C
ICONST_0
ACONST_NULL
ICONST_3
ACONST_NULL
INVOKESTATIC app/C$DefaultImpls.invoke$default (Lapp/C;ZLjava/lang/String;ILjava/lang/Object;)V
L3
LINENUMBER 389 L3
GETSTATIC app/C$D.INSTANCE : Lapp/C$D;
CHECKCAST app/C
ICONST_0
ACONST_NULL
ICONST_3
ACONST_NULL
INVOKESTATIC app/C$DefaultImpls.invoke$default (Lapp/C;ZLjava/lang/String;ILjava/lang/Object;)V
L4
Body of TestZach Klippenstein (he/him) [MOD]
05/27/2022, 5:16 AMBerkeli Alashov
05/27/2022, 5:23 AMBerkeli Alashov
05/27/2022, 5:26 AMste
05/27/2022, 8:17 AMLeland Richardson [G]
05/27/2022, 3:46 PMBerkeli Alashov
05/27/2022, 6:39 PMfun invoke
to fun C.invoke
and adding more arguments that are @Composable
lambdas also seems to work somehow..
While only adding @Composable
lambdas result in runtime error (non-nullable param is null)Leland Richardson [G]
05/27/2022, 7:12 PMC.invoke(…)
the compiler looks at it like a normal function call. The C()
pathway is an “operator call” and the code in the compose compiler was incorrectly assuming that in the latter pathway it would never have any default paramsBerkeli Alashov
05/27/2022, 8:34 PMC.
to @Composable operator fun invoke
to make it @Composable operator fun C.invoke
, and call it like C.D()
(which seems to be still an "operator call"?), it feels like it shouldn't be different calls?Leland Richardson [G]
05/27/2022, 8:45 PMBen Trengrove [G]
05/27/2022, 11:42 PMBerkeli Alashov
05/28/2022, 12:44 AMsealed interface A {
object B : A
sealed interface E : A {
object F : E
}
@Composable
operator fun invoke(truth: Boolean = true, data: String = "Data") {
assert(truth)
assert(data == "Data")
}
}
@Preview
@Composable
fun Test() {
// doesn't crash
A.B.invoke()
// crashes with: checkNotNullParameter, parameter data
A.E.F.invoke()
A.E.F()
// Crashes with already fixed assertion error (wrong defaults)
A.B()
}
Berkeli Alashov
05/28/2022, 1:58 AMminSize: Dp = Defaults.minSize()
field to invoke
with totally different stacktrace:
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object kotlin.jvm.functions.Function3.invoke(java.lang.Object, java.lang.Object, java.lang.Object)' on a null object reference
Class structure is same as above but invoke has a receiver : @Composable operator invoke A.invoke
Ben Trengrove [G]
05/31/2022, 12:34 AMBen Trengrove [G]
05/31/2022, 12:34 AMBerkeli Alashov
05/31/2022, 12:37 AMBerkeli Alashov
07/02/2022, 1:17 AMLeland Richardson [G]
07/02/2022, 2:22 AMBerkeli Alashov
07/02/2022, 2:50 AMsealed interface Button {
object Primary : Button
object Secondary : Button
sealed interface Outlined : Button {
object Primary : Outlined
object Secondary : Outlined
}
@Composable
operator fun invoke(
onClick: () -> Unit,
text: String,
modifier: Modifier = Modifier,
) {
androidx.compose.material3.Button(
onClick = onClick,
modifier = modifier,
) {
Text(text = text)
}
}
}
@Composable
@Preview
fun ButtonsPreview() {
Column {
// doesn't crash
Button.Primary(text = "Primary", onClick = {})
Button.Secondary(text = "Secondary", onClick = {})
// crashes
Button.Outlined.Primary(text = "Outlined Primary", onClick = {})
Button.Outlined.Secondary(text = "Outlined Secondary", onClick = {})
}
}
Berkeli Alashov
07/02/2022, 2:52 AMinterface Outlined : Button
, but not object Primary: Button
Ben Trengrove [G]
07/03/2022, 10:18 PMBerkeli Alashov
07/03/2022, 10:19 PMBen Trengrove [G]
07/03/2022, 10:40 PMLeland Richardson [G]
07/03/2022, 10:41 PMBen Trengrove [G]
07/03/2022, 10:42 PMBerkeli Alashov
07/03/2022, 10:44 PMBerkeli Alashov
07/03/2022, 10:46 PMinterface
too and doesn't with object, abstract/sealed class
Ben Trengrove [G]
07/03/2022, 11:02 PMBen Trengrove [G]
07/03/2022, 11:02 PMLeland Richardson [G]
07/03/2022, 11:14 PM