skip to content

You declared an extension function in a different file/package than where you want to call it. How do you make it usable, and why is this different from member functions?

level: juniorimportance: must knowfreq 70%

answer

  1. Extension = static function, receiver is first arg
  2. Import by NAME/package, not by receiver type
  3. Same file or same package = no import
  4. Members need no import; extensions do
  5. Use `as` alias to resolve name clashes

basics

~20 s

An extension defined elsewhere is only visible if you import it by name. Add an import line for that function, then call it like normal. Member functions come for free with the object's type, so they need no import.

solid answer

~40 s

Extension functions are resolved by their fully-qualified declaration site, not by the receiver's type. If the extension is in another package, you must `import com.pkg.fileOrTopLevel` — specifically `import com.pkg.myExtension` (the function name) or use a star import. Top-level extensions live on a synthetic file class, but you import the function symbol, not that class. This contrasts with member functions, which are part of the class API and are always visible wherever the type is. IDEs auto-add the import. Wildcard imports (`import com.pkg.*`) pull all top-level declarations including extensions. Note the import is by package + name; the receiver type is irrelevant to whether the import is needed.

code

kotlin · 9 lines
kotlin
// pkg a
package com.a
fun Int.squared() = this * this

// pkg b
package com.b
import com.a.squared        // import the symbol
// import com.a.squared as sq  // or alias on clash
fun demo() = 5.squared()    // 25

go deeper

for a junior

Knows extensions must be imported by name and that the IDE auto-adds the import.

for a middle

Explains extensions are static and resolved by declaration site, plus same-package visibility rules.

for a senior

Discusses wildcard vs aliased imports, name clashes, and overload ambiguity resolution.

for a principal

Frames import-by-symbol as an API-surface/discoverability tradeoff and guides package layout to keep extension visibility predictable across a large codebase.

## What an extension actually is An **extension function** like `fun String.shout() = uppercase() + "!"` is NOT added to the `String` class. The compiler turns it into a plain **static function** that takes the receiver as its first argument. Resolution is **static** and based on the declared (compile-time) type of the receiver. ## Why imports are needed Because the function is just a top-level symbol in some package, the only way the compiler knows it exists at a call site is if that symbol is **in scope**. It is in scope when: - it is declared in the **same file**, or - it is declared in the **same package** (same-package top-level declarations are visible without import), or - you **import** it explicitly. ```kotlin // file: strings/Shout.kt package com.app.strings fun String.shout(): String = uppercase() + "!" ``` ```kotlin // file: Main.kt package com.app import com.app.strings.shout // import by NAME, not by receiver type fun main() { println("hi".shout()) } ``` ## Import forms - **By name:** `import com.app.strings.shout` - **Wildcard:** `import com.app.strings.*` (brings all top-level symbols, including extensions) - **Alias:** `import com.app.strings.shout as bang` — useful when two extensions with the same name clash. ## Contrast with members A **member function** (declared inside the class body) is part of the type's API. Anywhere the type is visible, the member is callable with **no import**. Extensions never modify the class, so they have no such automatic visibility. ## Gotcha: overload ambiguity If two same-named extensions are imported from different packages and both apply, you get an ambiguity error; resolve with an `as` alias or a more specific import.

  • If the extension is in the same package but a different file, do you still need an import?
    No. Top-level declarations in the same package are visible across files without an import.
  • Two imported extensions have the same name and both apply. What happens?
    Overload resolution fails with an ambiguity error; fix it with an `as` alias or by importing only one.

An extension is like a freelancer with a business card: the object can only 'hire' them if you've got their card (the import) on hand; a member is a permanent employee always available.

saying these in an interview costs you the question

  • Says you import the receiver's class to use the extension
  • Claims extensions are added to the class so no import is ever needed
  • Thinks same-package different-file requires an import
  • Confuses extension visibility with the receiver type's visibility

context