Kotlin Traducido - Funciones de alcance (scope functions)

Martin Beltrame
Droid LATAM
Published in
3 min readMay 5, 2020

--

Unas de las tantas virtudes que tiene Kotlin como lenguaje son, la simplicidad, legibilidad y claridad con la que uno puede construir software sin esforzarse mucho.
La forma en que escribimos código debería ser un punto de continua mejora, en el cual siempre estemos buscando alternativas para hacer nuestras implementaciones más amenas. Por suerte, Kotlin nos permite ser más prolijos a pesar de que no tengamos esa intención, y parte de la “culpa” la tienen las scope functions.

Funciones cuyo único propósito es ejecutar un bloque de código dentro del contexto de un objeto

La librería estándar actualmente cuenta con las siguientes funciones de alcance: let, run, with, apply y also.

Ahora bien, ¿cuál es la diferencia entre cada una?

Hay dos elementos que las diferencian:

  • Cómo accedemos al objeto referenciado dentro del scope:
    - Para las funciones let y also accedemos mediante el it.
    -
    Para run, with y apply utilizamos this.
  • Qué valor retorna:
    - apply y also devuelven el objeto como tal.
    - let, run y with devuelven el valor de retorno del lambda, es decir, retorna el valor de nuestra última sentencia ejecutada.

Si bien todas realizan la misma función, lo que cambia, además de lo previamente mencionado, es el contexto, y es ahí donde debemos distinguir qué función conviene utilizar. let, por ejemplo, se suele utilizar en dos situaciones distintas, cuando queremos ejecutar un bloque de código solo con valores no nulos o para invocar una o más funciones con resultados en cadena. Unos ejemplos sencillos serían:

El run se suele utilizar cuando inicializamos una variable seguido de una interacción con la misma.
Tiene la particularidad de que no siempre es necesario utilizar el this para referenciar al objeto dentro del scope, como en el siguiente ejemplo:

En el caso del apply, es común utilizarlo para la inicialización de objetos.
Se lee como: aplicar las siguientes asignaciones al objeto.

also, tiene un buen uso cuando realizamos algunas acciones que no están estrictamente relacionadas con el objeto en sí, pero que lo utilizan como argumento.
Se lee como: y también realiza lo siguiente.

with, a diferencia de las demás funciones, pasa al objeto como parámetro en vez de ser el objeto quién llame a la función. Se suele utilizar en contextos donde no necesitamos obtener un resultado en sí mismo, sino que queremos aplicar una operación con/sobre el objeto.
Se lee como: con este objeto, hacemos lo siguiente.

Photo by Kevin Ku on Unsplash

¿Cómo estas funciones nos podrían ayudar a dar claridad a nuestro código?

Bueno, pongamos un ejemplo más cercano a la realidad para verlo con mejor perspectiva. Supongamos que tenemos la siguiente función, que sirve para actualizar una vista en Android.

¿Bastante engorroso a simple vista no?
Ahora cambiemos los if-else por scope functions. Nos quedaría algo como:

Obviamente cada una de las funciones elegidas pueden ser discutidas, en cuanto a si es el run o el apply el que debería usar, por dar un ejemplo, pero creo que podemos coincidir en que, la estructura completa del método (función en Kotlin) y la coherencia del código, es mucho más acertada que en la versión anterior.

Bonus Track:
Existen otras dos funciones que son muy útiles, pero que no entran en el espectro de las scope functions, que son takeIf y takeUnless. Estas funciones nos permiten ejecutar acciones dependiendo del estado del objeto. Si la condición se cumple, retorna el objeto y sino devuelve null.

Si combinamos las diferentes funciones, junto con el operador de nullabilidad ?., podemos notar cómo el código va tomando un formato más natural.

Como se indica en la documentación oficial:

Las funciones de alcance no introducen nuevas capacidades técnicas, pero pueden hacer que su código sea más conciso y legible.

Y esa es un poco la idea, seguir buscando alternativas para mejorar la calidad de nuestros programas.
Tus compañeros de trabajo te lo van a agradecer 😃.

return

--

--