Saltar a contenido

Funciones puras e impuras

En el desarrollo moderno con Kotlin y Jetpack Compose, las funciones puras son un pilar esencial. Nos permiten escribir código predecible, testable y eficiente, especialmente en arquitecturas declarativas donde la interfaz depende del estado.

¿Qué es una función pura?

Una función pura es aquella que:

  1. Depende únicamente de los parámetros que recibe.
    No utiliza variables externas ni accede a estados globales.

  2. No produce efectos secundarios.
    No modifica datos fuera de sí misma ni interactúa con el entorno (pantalla, ficheros, red, etc.).

  3. Siempre devuelve el mismo resultado para los mismos valores de entrada.

fun sumar(a: Int, b: Int): Int {
    return a + b
}

Características

  • Solo depende de sus argumentos.
  • No modifica nada fuera.
  • Es 100 % predecible → siempre que a = 3 y b = 2, el resultado será 5.

Ejemplo de función impura

var total = 0

fun sumarImpura(a: Int) {
    total += a   // modifica una variable global
}

Problemas

  • Depende del valor de total (estado externo).
  • Cambia el entorno → efecto secundario.
  • Llamarla dos veces con el mismo valor da resultados diferentes.

En Jetpack Compose

Compose está diseñado alrededor del concepto de funciones puras de interfaz: un composable ideal debería comportarse igual cada vez que recibe los mismos parámetros.

@Composable
fun Saludo(nombre: String) {
    Text("Hola, $nombre 👋")
}
Si vemos la integración en un ejemplo:

// Función pura: lógica de negocio
fun calcularDescuento(precio: Double, porcentaje: Double): Double {
    return precio - (precio * (porcentaje / 100))
}

// UI reactiva: Compose muestra el resultado
@Composable
fun CalculadoraDescuento() {
    var precio by remember { mutableStateOf("") }
    var porcentaje by remember { mutableStateOf("") }

    val resultado = if (precio.isNotBlank() && porcentaje.isNotBlank()) {
        calcularDescuento(precio.toDouble(), porcentaje.toDouble())
    } else null

    Column(modifier = Modifier.padding(16.dp)) {
        OutlinedTextField(
            value = precio,
            onValueChange = { precio = it },
            label = { Text("Precio original") }
        )

        OutlinedTextField(
            value = porcentaje,
            onValueChange = { porcentaje = it },
            label = { Text("Descuento (%)") }
        )

        resultado?.let {
            Text("Precio final: %.2f €".format(it), style = MaterialTheme.typography.titleMedium)
        }
    }
}

Fíjate que...

  • calcularDescuento() es pura → se puede probar en un test unitario.
  • CalculadoraDescuento() es impura → depende del estado de la UI y del framework Compose.
  • Separamos responsabilidades: lógica de negocio (pura) y presentación (reactiva).

Ventajas de las funciones puras

Ventaja Descripción
Predecibles Siempre devuelven el mismo resultado con los mismos datos.
Testeables Se pueden probar sin interfaz ni dependencias.
Reutilizables No dependen del contexto ni del framework.
Eficientes Facilitan recomposición y optimización en Compose.