Kotlin Avanzado - Contracts: Cómo volver al compilador de Kotlin más inteligente
Kotlin nunca deja de impresionarme con sus funcionalidades. Una función avanzada pero poco utilizada en el arsenal de Kotlin son los Contracts. Los contratos te permiten guiar al compilador de Kotlin para que tome mejores decisiones acerca de tu código, resultando en mejor seguridad ante nulos, mejor rendimiento o incluso menores errores en tiempo de ejecución.
Qué son los contratos de Kotlin?
Los contratos de Kotlin te permiten definir reglas acerca de como se comporta tu código, ayudando al compilador a hacer un análisis estático más avanzado. Los contratos habilitan funcionalidades como smart-casts y comprobaciones teniendo en cuenta el contexto, superando las capacidades básicas de Kotlin.
Por qué usar contratos?
- Mejora la seguridad ante nulos: Elimina las comprobaciones de nulos redundantes ayudando al compilador a saber cuando algo está garantizado que no sea nulo.
- Smart-casts optimizados: Hace que el compilador conozca el tipo de las variables en casos específicos.
- Reduce la repeticón de código: Escribe código más limpio e intuitivo delegando las comprobaciones repetitivas al compilador.
Ejemplos de contratos en Kotlin
1. Simplificar las comprobaciones de nuloss
Vamos a crear una función para validar valores no nulos:
|
|
Cómo los contratos nos ayudan aquí?
- La parte del contrato
returns() implies (value != null)
le dice al compilador:Si la función retorna de forma satisfactoria, entonces
value
está garantizado que no es nulo. - Esto habilita smart-casts, de manera que no tienes que volver a comprobar si es nulo manualmente una vez llamada esta función.
Algo muy similar se hace en las funciones require
y requireNotNull
de la librería estandar de Kotlin:
|
|
2. Afirmaciones personalizadas
Aquí se ve como los contratos pueden ser usados para definir afirmaciones personalizadas:
|
|
3. Smart-Casts con condiciones personalizadas
Vamos a crear una funcionalidad custom que comprueba si una valor coincide con un tipo específico. Esto demostrará como los contratos pueden ayudar a mejorar las comprobaciones:
|
|
Con esta implementación, el compilador sabe que dentro del bloque if
, input
es un String
, gracias al contrato definido en isOfType
. The la misma manera, el compilador sabe que inputInt
es de tipo Int
y no hace falta comprobar el tipo de nuevo.
4. Optimizando el control del flujo
Los contratos pueden simplificar el control del flujo habilitando al compilador para entender las invariantes o condiciones. Por ejemplo:
|
|
Salida
Processing 3 items
No items to process
No items to process
Cuando usar contratos
Los contratos son ideales para:
- Desarrollo de librerías: Proteger APIs públicas forzando condiciones pre existentes.
- DSLs y Frameworks: Simplificando la comprobación de tipos y validación de estados en DSLs de Kotlin.
- Optimizaciones en tiempo de ejecución: Reduce las comprobaciones en tiempo de ejecución al permitir al compilador inferir las condiciones en tiempo de compilación.
Conclusion
Los contratos de Kotlin son una gema oculta que pueden perfeccionar tu código mejorando la seguridad, reduciendo la repetición de código, y permitiendo un análisis por parte del compilador más inteligente. Tanto si estás creando librerías, escribiendo complejos DSLs, o simplemente optimizando código del día a día, los contratos proveen una herramienta muy poderosa para guiar al compilador de Kotlin y asegurando un código correcto.
Tener en cuenta que los contratos están anotados como funcionalidad experimental pero están implementados en Kotlin desde la versión 1.3 y se usan extensamente en la librería estandar de Kotlin así que son lo suficiente estables como para utilizarlos.