0Pricing
Kotlin Academy · Lesson

Scoped Extensions and Companion Extensions

Limit extension visibility and add extensions to companion objects.

Scoped Extensions and Companion Extensions is a free Kotlin Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Scope Extensions?

By default, extensions are visible wherever imported. Scoping limits visibility to a class, file, or context — reducing namespace pollution and improving discoverability.

File-Private Extensions

Mark an extension function private at file level to scope it to that file only.

private fun String.shout() = uppercase() + "!"
fun main() {
    println("hello".shout()) // HELLO!
}

Internal Visibility

Use internal to limit extensions to the current module — perfect for library internals not intended for external use.

internal fun List<Int>.sumIfPositive(): Int = filter { it > 0 }.sum()
fun main() {
    println(listOf(-1, 2, 3, -4).sumIfPositive()) // 5
}

Member Extension Functions

Declare an extension inside a class to make it usable only when an instance of that class is in scope. Has two receivers: dispatch (the class) and extension (the target).

class StringHelper(val prefix: String) {
    fun String.withPrefix() = prefix + this
    fun build(): String = "world".withPrefix() // calls extension via instance
}
fun main() {
    println(StringHelper("hello ").build()) // hello world
}

Member Extension Visibility

Member extensions are inaccessible from outside the dispatch class. Useful for encapsulation.

class Repo {
    fun List<Int>.allPositive() = all { it > 0 }
    fun check(xs: List<Int>) = xs.allPositive()
}
fun main() {
    val r = Repo()
    println(r.check(listOf(1, 2, 3))) // true
    // listOf(1).allPositive() // ERROR — no access
}

Extension on Companion Object

Add an extension to a class's companion object. Looks like a static method to callers but lives outside the class.

class Greeter {
    companion object
}
fun Greeter.Companion.morning() = "Good morning!"
fun main() {
    println(Greeter.morning())
}

Why Companion Extensions?

Useful for adding factory methods or helpers from outside the original class — without modifying it.

class User(val name: String) {
    companion object
}
fun User.Companion.guest() = User("Guest")
fun User.Companion.system() = User("System")
fun main() {
    println(User.guest().name)
    println(User.system().name)
}

Empty Companion Required

A class must declare a companion object (even empty) for companion extensions to attach. Otherwise the extension target doesn't exist.

class Box {
    companion object // required, even if empty
}
fun Box.Companion.create(): Box = Box()
fun main() {
    println(Box.create())
}

Scoped Extensions via Imports

You can scope use of an extension by importing it only in specific files. Files that don't import it can't see it.

// File A:
// fun String.shout() = uppercase()
// File B imports:
// import com.example.shout
// Only File B can call shout()
fun String.shout() = uppercase() + "!"
fun main() { println("hi".shout()) }

Extension Function via Scope Function

Use with or apply to temporarily bring an object into scope for extension use.

class StringTools {
    fun String.greet() = "Hello, $this!"
    fun process(name: String) = with(this) {
        name.greet()
    }
}
fun main() {
    println(StringTools().process("Ada"))
}

Extension Properties on Companion

Companion extensions can be properties too — add named constants from outside the class.

class HttpStatus {
    companion object
}
val HttpStatus.Companion.OK_CODE: Int get() = 200
val HttpStatus.Companion.NOT_FOUND: Int get() = 404
fun main() {
    println(HttpStatus.OK_CODE)
    println(HttpStatus.NOT_FOUND)
}

Best Practices

Use private for file-local helpers, internal for module-only APIs, member extensions for encapsulation, and companion extensions to add factory-like helpers from outside.

class StringUtils {
    companion object
}
fun StringUtils.Companion.isAlpha(s: String) = s.all { it.isLetter() }
fun main() {
    println(StringUtils.isAlpha("hello"))
    println(StringUtils.isAlpha("hi5"))
}

Quick Check

What's required on a class so you can add a companion extension to it from outside?

Recap

Scope extensions with private, internal, or as member extensions inside a class. Add companion extensions (functions or properties) from outside by attaching them to the class's declared companion object. Reduces namespace pollution while keeping code modular.

Frequently asked questions

Is the “Scoped Extensions and Companion Extensions” lesson free?

Yes — the full text of “Scoped Extensions and Companion Extensions” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.

What will I learn in “Scoped Extensions and Companion Extensions”?

Limit extension visibility and add extensions to companion objects. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Scoped Extensions and Companion Extensions” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Extension Functions: Syntax and Dispatch Rules
  2. Extension Properties and Computed Extensions
  3. Scoped Extensions and Companion Extensions
  4. Practical Extensions: Context, View & String Helpers
← Back to Kotlin Academy