En Kotlin, inline class (a partir de Kotlin 1.5 — el término "value class"), permite crear envoltorios sobre tipos con un costo mínimo. Durante la compilación, estas clases son reemplazadas en secreto por su valor interno (value) para evitar sobrecostes por la creación de objetos.
Restricciones y características:
=== no funciona como normalmente).Ejemplo:
@JvmInline value class UserId(val value: String) fun getUser(id: UserId) { println("Cargando usuario con id: ${id.value}") } val id = UserId("XYZ") getUser(id) // Bajo el capó, simplemente trabaja con String!
Cuándo usar:
¿Se puede heredar una value class o usarla en una jerarquía de interfaces/clases abstractas?
Respuesta: No, la value class no puede heredar otras clases (excepto interfaces), no puede ser abierta a la herencia, no permite el bloque init y otros campos no estáticos. La única opción disponible es implementar interfaces.
Ejemplo:
interface Validatable { fun isValid(): Boolean } @JvmInline value class Email(val raw: String) : Validatable { override fun isValid() = raw.contains("@") }
Historia
Una aplicación de Android experimentó un aumento repentino en el tiempo de inicio después de agregar value class a los parámetros Parcelable: se descubrió que un @Parcelize incorrecto con value class provocaba boxing/unboxing en cada etapa de la serialización, rompiendo las ventajas de inline.
Historia
Un microservicio comenzó a utilizar activamente value class para UserId y ProductId por motivos de seguridad de tipos, pero en muchos lugares las funciones genéricas requerían reflexión, que no funcionaba con la "envoltura". Las pruebas unitarias comenzaron a fallar inesperadamente, aparecieron ClassCastException.
Historia
El código migrado de Java comenzó a reemplazar las clases de dominio internas por value class para optimización, pero su uso como campos nulos llevó a excepciones de puntero nulo inesperadas, ya que la value class solo puede ser null si el valor externo también es null, lo que rompió invariantes antiguos.