Abhimanyu
04/01/2024, 3:48 AMinterface TestInterface {
fun emptyDefaultMethod() {}
}
fun TestComponent(
impl: TestInterface,
) {
if (impl == {} ) { // This doesn't work
// Do something
} else {
// Do something else
}
}
Usage without override for emptyDefaultMethod
TestComponent(object: TestInterface {})
Usage with override for emptyDefaultMethod
TestComponent(object: TestInterface {
override fun emptyDefaultMethod {
// Non empty override logic
}
})
Matthew Feinberg
04/01/2024, 10:46 AMval EMPTY_METHOD : ()->Unit = {}
interface TestInterface {
val myMethod: ()->Unit = EMPTY_METHOD
}
fun TestComponent(
impl: TestInterface,
) {
if (impl.myMethod === EMPTY_METHOD ) {
// Do something
} else {
// Do something else
}
}
TestComponent(object: TestInterface {})
TestComponent(object: TestInterface {
override val myMethod: ()->Unit get = {
// Do something
}
})
But.... there are SO many possible pitfalls to doing it this way, I'd be extremely wary of using it in production code.
You might also be able to do something with reflection to check if the method has been overridden or not (you probably won't be able to tell if it's empty or not though, just if it's been overridden). I'm not familiar enough with reflection on default implementations in interfaces...
But even that, I'd be super cautious about that in production code.
It might be better if you give some context about why you want do it and maybe someone might have a better (more idiomatic?) solution to suggest that doesn't involve checking if the method is empty or not.
(Also: Not sure this belongs in #android... it seems more like a general Kotlin question...)Abhimanyu
04/01/2024, 11:11 AMinterface TestInterface {
val customSlot: @Composable (() -> Unit)?
get() = null
}
fun TestComponent(
impl: TestInterface,
) {
if (impl.customSlot == null ) {
// Do something
} else {
// Do something else
}
}
Usage without override for emptyDefaultMethod
TestComponent(object: TestInterface {})
Usage with override for emptyDefaultMethod
TestComponent(object: TestInterface {
override val customSlot = @Composable {
// Slot code
}
})
Abhimanyu
04/01/2024, 11:15 AMAbhimanyu
04/01/2024, 11:17 AMMatthew Feinberg
04/01/2024, 11:18 AMMatthew Feinberg
04/01/2024, 11:18 AMAbhimanyu
04/01/2024, 11:19 AMfails on some platformsDoes this refer to platforms other than android?
Abhimanyu
04/01/2024, 11:19 AMMatthew Feinberg
04/01/2024, 11:22 AM@Composable
fun MyComponent(
firstSlot: @Composable ()->Unit = {}
) {
// Single common implementation here
}
Added slot:
@Composable
fun MyComponent(
firstSlot: @Composable ()->Unit = {},
secondSlot: @Composable ()->Unit = {}
) {
// Single common implementation here
}
// For backwards compatibility
@Composable
fun MyComponent(
firstSlot: @Composable ()->Unit = {}
) = MyComponent( firstSlot = firstSlot, secondSlot = {} )
Matthew Feinberg
04/01/2024, 11:23 AMMatthew Feinberg
04/01/2024, 11:25 AMMatthew Feinberg
04/01/2024, 11:30 AM@Composable
fun MyComponent(
firstSlot: (@Composable ()->Unit)? = null,
secondSlot: (@Composable ()->Unit)? = null
) {
// Single common implementation here
if( firstSlot == null ) {
} else {
}
}
// For backwards compatibility
@Composable
fun MyComponent(
firstSlot: (@Composable ()->Unit)? = null
) = MyComponent( firstSlot = firstSlot, secondSlot = null )
Abhimanyu
04/01/2024, 11:30 AMinterface ComponentSlots {
// Some slots
}
Usage
Component(
data = ComponentDataClass(),
eventHandler = {},
customSlots = object: ComponentCustomSlots {},
)
Adding new slot
interface ComponentSlots {
// Some slots
val slot1: @Composable (() -> Unit)?
get() = null
}
usage
Component(
data = ComponentDataClass(),
eventHandler = {},
customSlots = object: ComponentCustomSlots {
override val slot1 = @Composable {
// Slot 1 code
}
},
)
Abhimanyu
04/01/2024, 11:32 AMMatthew Feinberg
04/01/2024, 11:34 AMAbhimanyu
04/01/2024, 11:36 AMAbhimanyu
04/01/2024, 11:36 AMMatthew Feinberg
04/01/2024, 11:39 AMMatthew Feinberg
04/01/2024, 11:40 AMMatthew Feinberg
04/01/2024, 11:41 AMvararg
parameter at the end. Use a class with a private constructor for the type.
fun MyComponent(slotOne: ()->Unit = {}, slotTwo: ()->Unit = {}, vararg unused: NO_TRAILING_LAMBDA) {
}
Matthew Feinberg
04/01/2024, 11:42 AMclass NO_TRAILING_LAMBDA private constructor()
Matthew Feinberg
04/01/2024, 11:42 AMvararg
must be a named parameter. A trailing lambda is a compile error.Abhimanyu
04/01/2024, 11:42 AMfun Component1(
slot1: @Composable: () -> Unit
) {}
Usage
Component1 {
}
Adding new Slot
fun Component1(
slot1: @Composable: () -> Unit
slot2: @Composable: () -> Unit
) {}
breaks component1 existing usage.Abhimanyu
04/01/2024, 11:43 AMvararg
things looks like a nice idea.
Thanks, let me explore more on that. gratitude thank youMatthew Feinberg
04/01/2024, 11:46 AM