Kotlin DSL | Construcción del DSL: 5 — Operadores ‘plus’ y ‘minus’ y funciones ‘inline’
Sobrecarga de los operadores plus y minus y optimización de las funciones de orden superior con el marcador inline
Puedes ir a cualquier artículo de esta serie haciendo clic en alguno de los siguientes enlaces:
Kotlin DSL
- Introducción
- Conocimiento base para construir DSLs con Kotlin — Parte 1
- Conocimiento base para construir DSLs con Kotlin — Parte 2
- Código Base: Proyecto Shapes-DSL
- Construcción del DSL: 1 — Organización de paquetes y el objeto ‘Panel’
- Construcción del DSL: 2 — El objeto ‘Cuadrado’
- Construcción del DSL: 3 — Los objetos ‘Triángulo’ y ‘Rombo’
- Construcción del DSL: 4 — Espacios en blanco y el objeto ‘Figura Compuesta’
- Construcción del DSL: 5 — Los operadores ‘plus’ y ‘minus’ y funciones ‘inline’
- Construcción del DSL: 6 — La anotación @DslMarker
- Experimentación y conclusiones
En el artículo anterior quedaron definidas las funciones space
y composed
que agregan espacios en blanco y figuras compuestas dentro del Panel respectivamente. También se definieron funciones infix para crear figuras compuestas de una manera más idiomática. Al final del artículo anterior, el código del método main
lucía así:
En este artículo sobrecargaremos los operadores +
y -
para combinar figuras con las operaciones de unión e intersección. El código del método main
al que debemos llegar es el siguiente:
Sobrecarga de los operadores ‘plus’ y ‘minus’
Para sobrecargar los operadores +
y -
debemos nombrar a las funciones plus
y minus
respectivamente. El objetivo es combinar 2 figuras de cualquier tipo, es decir, 2 objetos de tipo Shape
y que sus resultados correspondan a los de las operaciones de unión e intersección. Claramente serán dos funciones idénticas a las funciones infix union
e intersection
, por lo tanto, los signatures de las funciones serán los siguientes:
operator fun Shape.plus(shape: Shape): ComposedShape
operator fun Shape.minus(shape: Shape): ComposedShape
💬 Recuerda que para sobrecargar operadores debes marcar las funciones con el modificador
operator
.
La función plus
debe hacer lo mismo que hace la función union
y para evitar el código duplicado sería mejor invocar a la función union
y retornar su resultado. Con la función minus
hacemos exactamente lo mismo con la diferencia de que se corresponde con la función intersection
.
Desplázate hasta el paquete console_shapes_dsl.external
y añade el siguiente código en el archivo Extension.kt
:
💬 Si ejecutas el código verás que nuevamente funciona.
Finalmente hemos logrado nuestro objetivo. Creamos un DSL para substituir el código inicial…
…por un código más idiomático…
Aunque ya está el DSL listo, aún queda por hacer una pequeña optimización y afinarlo un poco.
Optimización
En el artículo Conocimiento base para construir DSLs con Kotlin — Parte 2 mostré el funcionamiento de las funciones inline y por qué algunas veces son necesarias.
Para mejorar el rendimiento del DSL podemos marcar todas las funciones de orden superior con el modificador inline
. En el artículo mencioné que para que una función sea marcada como inline
debe cumplir con los siguientes 3 puntos:
— La función es llamada muchas veces y de manera frecuente.
— La función recibe uno o más lambdas como argumento.
— La función no supera las 4 líneas de código.
Las funciones panel
, square
, triangle
, rhombus
y composed
cumplen con el segundo y tercer punto, pero el primer punto no se cumple para ninguna y marcar dichas funciones no representaría una ganancia significativa en rendimiento. Sin embargo, el DSL permite perfectamente que se añadan muchos objetos al Panel por medio de ciclos for
y aunque ese no sea nuestro caso según el código final, cualquiera podría hacerlo de esa manera sin ningún límite más que el de la memoria física.
Vamos a hacer esa pequeña optimización para hacerlo eficiente en caso de que se añadan muchas figuras invocando a dichas funciones de manera frecuente.
Desplázate hasta el paquete console_shapes_dsl.external
y modifica el archivo Extension.kt
marcando las funciones panel
, square
, triangle
, rhombus
y composed
con el modificador inline
. El código de dichas funciones quedaría de la siguiente manera:
💬 Puedes probar la aplicación ejecutando el código, sin embargo, la ganancia en rendimiento es imperceptible. El cambio hecho es meramente simbólico y lo muestro solo para que lo tengas presente.
Aunque ya tenemos un DSL funcional, aún queda un pequeño detalle muy importante que debes tener en cuenta y que tiene que ver con el control dentro de los ámbitos de los bloques de código de los lambdas de las funciones de orden superior. Esto lo veremos en el siguiente artículo.
Continúa en el siguiente artículo con Construcción del DSL: 6 — La anotación @DslMarker
- Puedes acceder a la documentación oficial sobre funciones de orden superior y lambdas en el siguiente enlace: https://kotlinlang.org/docs/lambdas.html
- Puedes acceder a la documentación oficial sobre lambdas con receptor en el siguiente enlace: https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver
- Puedes acceder a la documentación oficial sobre funciones de ámbito en el siguiente enlace: https://kotlinlang.org/docs/scope-functions.html