Historia del tema:
Con el aumento de la popularidad de la programación funcional y las expresiones lambda en la JVM, surgió un problema de sobrecarga en objetos anónimos y llamadas de métodos adicionales. En Java, esto se encuentra en el uso de interfaces funcionales. En Kotlin, se introdujo la palabra clave inline para evitar asignaciones innecesarias al pasar funciones lambda.
Problema:
La llamada de una función con parámetros lambda crea objetos anónimos en la memoria y aumenta la profundidad de la pila, lo que ralentiza la ejecución del código, especialmente cuando se usa activamente en ciclos y llamadas anidadas.
Solución:
Kotlin permite declarar una función con el modificador inline, después de lo cual el cuerpo de la función y las lambdas pasadas se insertan directamente en el lugar de la llamada durante la compilación. Esto permite al compilador deshacerse de asignaciones adicionales y mejorar el rendimiento, especialmente para funciones cortas y frecuentemente llamadas (por ejemplo, la filtración de colecciones).
Ejemplo de código:
inline fun <T> Iterable<T>.myFilter(predicate: (T) -> Boolean): List<T> { val result = mutableListOf<T>() for (item in this) if (predicate(item)) result.add(item) return result } val filtered = listOf(1, 2, 3, 4).myFilter { it % 2 == 0 } println(filtered) // [2, 4]
Características clave:
noinline y crossinline para controlar el inlining de lambdas individuales.¿Se puede usar una función inline con cualquier parámetro funcional o tipo genérico T?
No, las funciones inline ahorran principalmente en la sobrecarga de llamadas para parámetros lambda, pero el propio parámetro genérico (por ejemplo, T) no se inliniza: para esto se necesita el modificador reified. Para simples T sin reified, la información del tipo se perderá en la etapa de compilación.
¿Qué sucederá si en una función inline se declara una clausura sobre una variable de un alcance externo?
Las variables del alcance externo se copian dentro de la expresión inlinada. Todos los accesos a ellas funcionarán como si el código estuviese realmente insertado. Esto puede llevar a un comportamiento inesperado si no se esperan efectos secundarios.
¿Se puede llamar a una función inline desde código Java?
Sí, pero se compilará como una función normal, y el código Java no verá ninguna ventaja del inlining. Kotlin logra optimización solo al usar funciones inline desde el código Kotlin.
return en lambdas inline: control de flujo incorrectoUn desarrollador inlina una función larga con varias lambdas de filtrado y post-procesamiento, esperando aceleración. El código se compila lentamente, el APK/RAR/DEX resultante aumenta significativamente, y no hay aumento en la velocidad.
Pros:
Contras:
Se implementa una pequeña función inline para filtros cortos de arreglos, llamada cientos de veces en un ciclo caliente, donde el tiempo de ejecución es crítico. La cantidad de asignaciones de memoria es mínima, ya que la lambda no crea un objeto anónimo.
Pros:
Contras: