A few weeks ago, I had to create an extension function - a usual task for any Kotlin developer. But there were a few limitations:
- The receiver was a common type, polluted with too many methods.
- The extension function was only relevant to my feature package.
- Creating a
Gradlemodule was out of scope. - Introducing a new type to hold the function felt like too much.
- Kotlin doesn’t support package-private, yet.
So how can I have the advantages of using extension functions but avoid these issues?
One way is to use objects as namespace for extension functions.
Here is an example:
// feature/MyFeatureActivityManagers.kt
// Namespace object.
internal object MyFeatureActivityManagers {
// Extension functions that are only interested to my feature.
fun ActivityManager.doSomethingThatOnlyYouCare() = TODO("")
fun ActivityManager.doSomethingThatOnlyYouCareToo() = TODO("")
}
And here is the usage:
// feature/MyFeature.kt
import MyFeatureActivityManagers.doSomethingThatOnlyYouCare
fun myFeature(activityManager: ActivityManager) {
activityManager.doSomethingThatOnlyYouCare()
}
It didn’t change much but the approach has a few advantages:
- It ensures that code in the same package can only access the extension function with a direct import;
- It helps humans, and tools, to identify what file the extension is coming from;
- But most important, it has the right level of discoverability*.
What I mean with discoverability is that IntelliJ IDEA seems to have a hierarchy for suggesting auto-complete in the following order:
- Member functions
- Global extensions
- Object extensions
Hence, IDEA will only suggest to other developers your shiny function if they are actively looking for it.
What’s up with the naming?
I want to indicate why these particular functions are related, given the infinite number of possible extensions I could write.
A pattern I find useful is: {Context}{Receiver}s
, where:
Context
groups the functions based on their relevance.Receiver
refers to the type of the receiver for these functions.s
represents the collection of extensions.
Wrapping up
If you find yourself creating extensions that should be limited in access, consider creating a namespace object for them. That will help your project with organization and readability.
Credits
Special thanks to Maria Chietera, and Jacob Rein proofread review! 🔍
ℹ️ To stay up to date with my writing, follow me on Twitter or Mastodon. If you have any questions or I missed something, feel free to reach out to me! ℹ️