There is a Kotlin trick I always wanted to achieve but I'm not sure it is possible.
Can we add an extension function to a class, but having another receiver type ?
as an example, let's imagine we want to add a function launchInViewModelScope()
to the abstract class ViewModel
. But we want this function to be only callable by Flow<*>
.
ViewModel
and Flow
are part of kotlin so we have to use extension functions.
This behavior is possible when adding the extension function inside the class body, but here we can't add functions inside ViewModel
body.
Iow I'm looking for a solution to write something like this :
ViewModel.Flow<*>.launchInViewModelScope() { /* doWork */}
ViewModel
, that would be too easy :D.ViewModelScope
instance.Here is a skeleton of the same question with code :
/** SUPPOSE A AND B ARE DEFINED IN A LIBRARY **/
abstract class A {
fun B.doSomeThing() {
println("something")
}
}
class B {
}
/*********************************************/
// Is there an existing way to achieve something like this ?
fun A.B.doSomeThingElse() {
println("somethingElse")
}
// That can allow me to do this :
class AImpl: A() {
val b = B()
fun main() {
// This works as expected
b.doSomeThing()
// I want this to work :
b.doSomeThingElse()
}
}
class C {
val b = B()
fun main() {
// I want this NOT to work :
b.doSomeThingElse()
}
}
Context receivers is the feature you need. Pass the -Xcontext-receivers
compiler option to enable this experimental feature. Then you can write:
context(A)
fun B.doSomeThingElse() {
println("somethingElse")
}
You have access to the instance of A
in the function body as if it is an extension receiver. If you need to unambiguously refer to it, you can say this@A
.