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?
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:
run
; orrun
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.
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.