How does Kotlin disambiguate function calls, constructors, companion objects and invocation overloads? In Kotlin 1.3.11
, I can declare two homonymous members in the same scope:
fun main(args: Array<String>) {
val test = object {
operator fun invoke() = println("test invocation")
}
test() // Prints: "test invocation"
// I think this should fail to compile, but it works
fun test() = println("test function")
test() // Prints: "test function"
}
You might think it uses the most recent declaration, but not so!
fun main(args: Array<String>) {
fun test() = println("test function")
val test = object {
operator fun invoke() = println("test invocation")
}
test() // Prints: "test function"
}
But there is also some weird interaction with scope. If I move the function declaration outside:
fun test() = println("test function")
fun main(args: Array<String>) {
val test = object {
operator fun invoke() = println("test invocation")
}
test() // Prints "test invocation"
}
Similarly, if I move the object outside, this also compiles:
val test = object {
operator fun invoke() = println("test invocation")
}
fun main(args: Array<String>) {
fun test() = println("test function")
test() // Prints: "test function"
}
I can also move them both outside:
val test = object {
operator fun invoke() = println("test invocation")
}
fun test() = println("test function")
fun main(args: Array<String>) {
test() // Prints: "test function"
}
But if I overload test
using a class name, it does not compile:
class test {} // Does not compile
fun test() = println("test function")
val test = object {
operator fun invoke() = println("test invocation")
}
Attempting to compile this program results in the following error:
Error:(1, 6) Conflicting overloads: public fun test(): Unit defined in root package in file Simplest version.kt, public constructor test() defined in test, public val test: Any defined in root package in file Simplest version.kt, public final class test defined in root package in file Simplest version.kt
Error:(1, 6) Conflicting declarations: public fun test(): Unit, public constructor test(), public val test: Any, public final class test
Error:(2, 0) Conflicting overloads: public fun test(): Unit defined in root package in file Simplest version.kt, public constructor test() defined in test, public val test: Any defined in root package in file Simplest version.kt, public final class test defined in root package in file Simplest version.kt
Error:(3, 4) Conflicting declarations: public fun test(): Unit, public constructor test(), public val test: Any, public final class test
However it does compile when using a nested scope:
class test {
constructor() {
println("test constructor")
}
}
fun main(args: Array<String>) {
fun test() = println("test function")
val test = object {
operator fun invoke() = println("test invocation")
}
test() // Prints: "test function"
}
There is also some ambiguity between companion objects and constructors:
class test {
constructor() {
println("test constructor")
}
companion object {
operator fun invoke() = println("test companion invocation")
}
}
fun main(args: Array<String>) {
test() // Prints: "test constructor"
}
Somehow, the following example also compiles:
class test {
constructor() {
println("test constructor")
}
companion object {
operator fun invoke() = println("test companion invocation")
}
}
fun main(args: Array<String>) {
test() // Prints: "test constructor"
val test = object {
operator fun invoke() = println("test invocation")
}
test() // Prints: "test invocation"
fun test() = println("test function")
test() // Prints: "test function"
}
This is even less intuitive:
class test {
constructor() {
println("test constructor")
}
companion object {
operator fun invoke() = println("test companion invocation")
}
operator fun invoke() = println("test invocation overload")
}
fun main(args: Array<String>) {
val test = test() // Prints: "test constructor"
val test1 = test() // Prints: "test invocation overload"
}
What are the rules for overloading named members and why will the Kotlin compiler accept invocable variables and homonymous functions in the same scope, but not in the presence of a homonymous class (in certain cases, but not others)? Also, how does invoke work in the presence of a scoped constructor or companion object with the same call site syntax?