Can Kotlin extension functions be called without an import declaration?
Asked Answered
P

1

6

Is it possible to call an extension function from another package without importing it?

Given an extension function:

package ext
fun Int.plusOne() = this + 1

Is there any way to call this function without importing the function first?

I can call non-extension functions without an import (ignore that the function does not need to be imported, just note that the syntax is valid):

val el: List<Int> = kotlin.emptyList()

I can instantiate classes without an import:

val str = java.lang.String("yo.")

But I have not yet found the equivalent for extensions (I know some examples are silly):

val i = 42
// All those are not valid syntax...

i.ext.plusOne()

ext.plusOne(i)

i.(ext.plusOne)()

i.(ext.plusOne())

ext.i.plusOne()

val pO = ext.plusOne
i.pO()

Bonus: Same question, but for extension properties.

Edit: To add to the list of invalid examples, even at places where the extension receiver is implicit, FQDNs are not allowed:

// Good:
import ext.plusOne
val four = with(3) { plusOne() }

// Unresolved reference:
val four = with(3) { ext.plusOne() }
Pathway answered 17/2, 2023 at 10:48 Comment(0)
I
6

No, according to the spec. A call can only be these forms:

  • A fully-qualified call without receiver: package.foo();
  • A call with an explicit receiver: a.foo();
  • An infix function call: a foo b;
  • An overloaded operator call: a + b;
  • A call without an explicit receiver: foo().

Notice that the "fully-qualified call" form, which is the only form that allows the use of package names, explicitly says "without receiver". However, your plusOne requires an Int as a receiver. In fact, by definition, all extensions functions/properties require a receiver by definition.

I also tried looking at callable references, in hopes of making a callable reference to plusOne using a fully qualified name, and then calling that callable reference. However, it turns out the syntax for those is even stricter.

Therefore, this cannot be done without modifying the ext package in some way, like adding a "wrapper" function.

After all, there is really no need for such a feature. Importing is not that hard - the IDE does it all for you these days. If you need to import two things with the same name, use an import alias:

import package1.extFunc as pack1ExtFunc
import package2.extFunc as pack2ExtFunc
Irritant answered 17/2, 2023 at 11:34 Comment(2)
It could be useful if we write a code generator. Then it is much easier to use absolute names and keep various parts of the generated code entirely independent of each other. Managing imports, detecting name conflicts, etc. is pretty annoying in this case, however, utils like KotlinPoet do this for us. Similar problems may occur if using Kotlin for scripting or processing fragments of executable Kotlin code. Code with absolute names is more "independent", it can be enclosed in a function and should just work.Iridescent
@Iridescent That is exactly where I'm coming from. I'm currently writing Kotlinpoet-invoking code, and test it by using the toString() method, which, when applied to *Specs other than FileSpec does not generate import statements, and instead generates my first invalid syntax from the OP. I was just wondering if there actually might be a way to have completely import-free files that are valid Kotlin.Pathway

© 2022 - 2024 — McMap. All rights reserved.