Setup:
interface AProvider {
fun getA(): String
}
interface BProvider {
fun getB(): String
}
fun a(block: AProvider.() -> Unit) {}
fun b(block: BProvider.() -> Unit) {}
With this, I can nest the two functions as follows
val x = a { b { getA(); getB() } }
Now I would like to abstract this particular pattern to a higher level function so that I can pass the inner block and call both getA()
and getB()
in it, e.g. something like this:
val y = { l: ??? -> a { b(l) } }
val z = y { getA(); getB() }
The questions are
- Is this possible with the proposed definition of
y
? - If yes, what should be the type of
l
? - If not, is there some other definition where I can get access to multiple dispatch receivers inside a lambda?
Note: This is related to my other SO question
CodePudding user response:
You can do this with context receivers, which allows you to specify multiple receivers for one lambda. The type of y
would be:
(context(AProvider, BProvider) () -> Unit) -> Unit
That is, a function that takes another function as a parameter, and returns Unit
. The function parameter that it takes also returns Unit
, but has AProvider
and BProvider
as its context receivers.
val y: (context(AProvider, BProvider) () -> Unit) -> Unit = { l ->
a { b { l(this@a, this@b) } }
}
val z = y { getA(); getB() }
Notice that when we call l
, we pass the context receivers, this@a
and this@b
, as if they are regular parameters.
This makes z
a Unit
as well, which is kind of weird. y
returns whatever a
returns after all, so perhaps you did not intend a
to return Unit
.