An In-depth Exploration of Inline, Noinline, Crossinline, and Reified in Kotlin

Ranjeet
The Fresh Writes
Published in
5 min readFeb 4, 2023
Photo by Marc Reichelt on Unsplash

Kotlin provides several keywords to control the behavior of inline functions. These keywords include inline, noinline, crossinline, and reified. Let's take a closer look at each of these keywords and see how they can be used to optimize the performance of your code.

inline

The inline keyword is used to indicate that a function should be inlined, meaning that the code of the function will be directly inserted into the call site, rather than being called as a separate function. Inlining can have significant performance benefits, as it eliminates the overhead of function call and return.

Here’s an example of an inline function:

inline fun add(a: Int, b: Int): Int {
return a + b
}

n this example, the add function is marked as inline, so it will be inlined at the call site. This can lead to improved performance, especially if the add function is frequently called and has no side effects.

Another example of an inline function is:

inline fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}

noinline

The noinline keyword is used to prevent a lambda expression from being inlined. It is used in conjunction with inline functions, and is often used to pass a lambda as an argument to another function.

Here’s an example of using noinline:

inline fun addAndRun(a: Int, b: Int, noinline action: (Int) -> Unit) {
val sum = a + b
action(sum)
}

In this example, the addAndRun function is marked as inline, but the action lambda is marked as noinline. This means that the action lambda will not be inlined, even though the addAndRun function will be. This can be useful when you want to pass a large or complex lambda to another function, as it can reduce the size of the generated code.

Another example of using noinline is:

inline fun runIfPositive(a: Int, b: Int, noinline successAction: (Int) -> Unit, noinline failureAction: (Int) -> Unit) {
if (a + b > 0) successAction(a + b) else failureAction(a + b)
}

In this example, both successAction and failureAction are marked as noinline. This means that both lambdas will not be inlined, even though the runIfPositive function will be. This can be useful when you want to pass two large or complex lambdas to another function, as it can reduce the size of the generated code.

crossinline

The crossinline keyword is used to indicate that a lambda expression should not be allowed to return from the function that it was passed to. It is used in conjunction with inline functions.

Here’s an example of using crossinline:

inline fun runIfPositive(
a: Int, b: Int, crossinline successAction: () -> Unit,
crossinline failureAction: () -> Unit
) {
if (a + b > 0) successAction() else failureAction()
}

In this example, both successAction and failureAction are marked as crossinline. This means that neither of the lambdas are allowed to contain a return statement, and any attempt to do so will result in a compile-time error. This can be useful when you want to pass a lambda as an argument, but want to ensure that it does not return from the function it was passed to.

Another example of using crossinline is:

inline fun repeat(times: Int, crossinline action: () -> Unit) {
for (i in 0 until times) action()
}

In this example, the action lambda is marked as crossinline. This means that it is not allowed to contain a return statement, and any attempt to do so will result in a compile-time error. This can be useful when you want to pass a lambda as an argument to repeat a certain action, but want to ensure that it does not return from the function it was passed to.

reified

The reified keyword is used to allow access to the type information of a type parameter at runtime. This can be useful when you want to perform type-specific operations within a function.

Here’s an example of using reified:

inline fun <reified T> getTypeName(): String {
return T::class.simpleName
}

In this example, the getTypeName function is marked as reified. This means that the type information of the type parameter T is available at runtime, and can be used to obtain the simple name of the class using the ::class syntax. This can be useful when you want to perform type-specific operations within a function, such as checking the type of an object.

Another example of using reified is:

inline fun <reified T> isType(value: Any): Boolean {
return value is T
}

In this example, the isType function is marked as reified. This means that the type information of the type parameter T is available at runtime, and can be used to check if a value is of the specified type using the is operator. This can be useful when you want to perform type-specific operations within a function, such as checking the type of an object.

These keywords provide fine-grained control over the behavior of inline functions in Kotlin, and can be used to optimize the performance of your code. Whether you’re using inline to improve performance, noinline to pass complex lambdas, crossinline to prevent returns from within passed lambdas, or reified to access type information at runtime, these keywords can help you write more efficient and flexible code.

It’s important to note that while using these keywords can improve performance, they also have some trade-offs. For example, using inline functions increases the size of the generated code, as the function body is copied into every call site. Additionally, using reified can also increase the size of the generated code, as type information is stored in the resulting class files.

However, in most cases, the performance benefits of using these keywords outweigh the downsides, and they are widely used in many Kotlin projects. By understanding the different uses and implications of inline, noinline, crossinline, and reified, you can make informed decisions about when and how to use them in your own code.

In conclusion, Kotlin’s inline functions provide a powerful tool for optimizing your code and improving performance. Whether you’re writing a small utility function or a complex library, these keywords can help you write more efficient and flexible code. So, it’s important to understand the different uses and implications of each keyword, and make informed decisions about when and how to use them in your own code.

Thanks for reading.Happy learning 😄

Do support our publication by following it

Also refer to the following articles

--

--