Is there a way to call a non-context function from...
# getting-started
r
Is there a way to call a non-context function from within a context function of the same name?
Copy code
fun generate(selection: Selection, values: Values) { ... }
context(Scope) fun generate(selection: Selection, values: Values) =
    generate(this@Scope.selection refine selection, values)
       ^ this is a recursive call, but I would like to call the other (non context(Scope)) generate function
y
Oh boy, that's a tough one. Currently, I think there's no way to remove receivers from a scope, which limits any neat solutions we can come up with. Simplest workaround: have a bridge method:
Copy code
fun generate(selection: Selection, values: Values) { ... }
private fun _generate(selection: Selection, values: Values) = generate(selection, values)
context(Scope) fun generate(selection: Selection, values: Values) =
    _generate(this@Scope.selection refine selection, values)
Here's a neat-ish solution that has a lot of overhead sadly (because it creates a function reference):
Copy code
fun generate(selection: Selection, values: Values) {}

context(Scope) fun generate(selection: Selection, values: Values) {
    val generate: (Selection, Values) -> Unit = ::generate
    generate(this@Scope.selection refine selection, values)
}
Interestingly, something like KT-44530 will remove that overhead (which, shameless plug, I've been working on a compiler plugin for, but I haven't yet updated to 1.6.20)
Overheadless solution: define a few utility functions that invoke without a context like-a so:
Copy code
fun generate(selection: Selection, values: Values) {}

context(Scope) fun generate(selection: Selection, values: Values): Unit = 
    invokeContextless(::generate, /*this@Scope,*/ this@Scope.selection refine selection, values)

inline fun <A, B, R> invokeContextless(action: (A, B) -> R, a: A, b: B): R = action(a, b)
inline fun <A, B, C, R> invokeContextless(action: (A, B, C) -> R, a: A, b: B, c: C): R = action(a, b, c)
The compiler seems to understand which function you intend by that function reference based on the amount of parameters that you pass to
invokeContextless
, try that out yourself by uncommenting the
this@Scope
. Personally, this is a well-balanced solution in that it's concise enough but it doesn't sacrifice performance. I would've preferred however if instead the function reference solution would've had no overhead, or if we could get a way to remove receivers from a scope
r
Indeed. I think I'll stick with the utility function approach for now, but I'll definitely keep an eye on that plugin. Thanks again for the help.