Search code examples
kotlinextension-methodsoverload-resolution

How can one invoke the non-extension `run` function (the one without scope / "object reference") in environments where there is an object scope?


Example:

data class T(val flag: Boolean) {
    constructor(n: Int) : this(run {
        // Some computation here...
        <Boolean result>
    })
}

In this example, the custom constructor needs to run some computation in order to determine which value to pass to the primary constructor, but the compiler does not accept the run, citing Cannot access 'run' before superclass constructor has been called, which, if I understand correctly, means instead of interpreting it as the non-extension run (the variant with no object reference in https://kotlinlang.org/docs/reference/scope-functions.html#function-selection), it construes it as a call to this.run (the variant with an object reference in the above table) - which is invalid as the object has not completely instantiated yet.

What can I do in order to let the compiler know I mean the run function which is not an extension method and doesn't take a scope?

Clarification: I am interested in an answer to the question as asked, not in a workaround.

I can think of several workarounds - ways to rewrite this code in a way that works as intended without calling run: extracting the code to a function; rewriting it as a (possibly highly nested) let expression; removing the run and invoking the lambda (with () after it) instead (funnily enough, IntelliJ IDEA tags that as Redundant lambda creation and suggests to Inline the body, which reinstates the non-compiling run). But the question is not how to rewrite this without using run - it's how to make run work in this context.

A good answer should do one of the following things:

  • Explain how to instruct the compiler to call a function rather than an extension method when a name is overloaded, in general; or
  • Explain how to do that specifically for run; or
  • Explain that (and ideally also why) it is not possible to do (ideally with supporting references); or
  • Explain what I got wrong, in case I got something wrong and the whole question is irrelevant (e.g. if my analysis is incorrect, and the problem is something other than the compiler construing the call to run as this.run).

If someone has a neat workaround not mentioned above they're welcome to post it in a comment - not as an answer.

In case it matters: I'm using multi-platform Kotlin 1.4.20.


Solution

  • Kotlin favors the receiver overload if it is in scope. The solution is to use the fully qualified name of the non-receiver function:

    kotlin.run { //...
    

    The specification is explained here.

    Another option when the overloads are not in the same package is to use import renaming, but that won't work in this case since both run functions are in the same package.