Kotlin’s inline
functions offer powerful performance optimizations, but when used in public APIs, they come with specific restrictions. Understanding these limitations helps ensure compatibility, maintainability, and adherence to best coding practices.
In this blog, we’ll explore the restrictions for public API inline functions and discuss ways to work around them.
Restrictions for public API inline functions
In Kotlin, when you have an inline function that is public or protected, it is considered part of a module’s public API. This means that other modules can call that function, and the function itself can be inlined at the call sites in those modules.
However, there are certain risks of binary incompatibility that can arise when changes are made to the module that declares the inline function, especially if the calling module is not re-compiled after the change.
To mitigate these risks, there are restrictions placed on public API inline functions. These functions are not allowed to use non-public-API declarations, which include private and internal declarations and their parts, within their function bodies.
Using Private Declarations
private fun privateFunction() {
// Implementation of private function
}
inline fun publicAPIInlineFunction() {
privateFunction() // Error: Private declaration cannot be used in a public API inline function
// Rest of the code
}
In this scenario, we have a private function privateFunction()
. When attempting to use this private function within the public API inline function publicAPIInlineFunction()
, a compilation error will occur. The restriction prevents the usage of private declarations within public API inline functions.
Using Internal Declarations
internal fun internalFunction() {
// Implementation of internal function
}
inline fun publicAPIInlineFunction() {
internalFunction() // Error: Internal declaration cannot be used in a public API inline function
// Rest of the code
}
In this scenario, we have an internal function internalFunction()
. When trying to use this internal function within the public API inline function publicAPIInlineFunction()
, a compilation error will arise. The restriction prohibits the usage of internal declarations within public API inline functions.
To eliminate this restriction and allow the use of internal declarations in public API inline functions, you can annotate the internal declaration with @PublishedApi
. This annotation signifies that the internal declaration can be used in public API inline functions. When an internal inline function is marked with @PublishedApi
, its body is checked as if it were a public function.
Using Internal Declarations with @PublishedApi
@PublishedApi
internal fun internalFunction() {
// Implementation of internal function
}
inline fun publicAPIInlineFunction() {
internalFunction() // Allowed because internalFunction is annotated with @PublishedApi
// Rest of the code
}
In this scenario, we have an internal function internalFunction()
that is annotated with @PublishedApi
. This annotation indicates that the internal function can be used in public API inline functions. Therefore, using internalFunction()
within the public API inline function publicAPIInlineFunction()
is allowed.
By applying @PublishedApi
to the internal declaration, we explicitly allow its usage in public API inline functions, ensuring that the function remains compatible and can be safely used in other modules.
So, the restrictions for public API inline functions in Kotlin prevent them from using non-public-API declarations. However, by annotating internal declarations with
@PublishedApi
, we can exempt them from this restriction and use them within public API inline functions, thereby maintaining compatibility and enabling safe usage across modules.
This is just a part..! Read the full version here: [Main Article URL]
Conclusion
Restrictions for public API inline functions are crucial for ensuring stability and maintainability. While inline functions provide performance benefits, they must be used cautiously in public APIs to prevent breaking changes, excessive code duplication, and accessibility issues.
These restrictions help maintain binary compatibility and ensure that code remains adaptable to future changes. Understanding them and following best practices allows you to write efficient and robust Kotlin code that is both scalable and maintainable.
When designing public APIs with inline functions, always consider factors like binary compatibility, accessibility, and maintainability. Adhering to these principles helps you avoid unexpected issues while keeping your Kotlin code clean, efficient, and future-proof.