En pocas palabras, las restricciones significan que hay menos formas correctas de unir las cosas, y las funciones de primera clase hacen que sea más fácil eliminar cosas como las estructuras de bucle. Tome el bucle de esta respuesta , por ejemplo:
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
iterator.remove();
}
}
Esta es la única forma segura e imperativa en Java de eliminar un elemento de una colección mientras está iterando a través de él. Hay muchas maneras que parecen muy cercanas, pero están equivocadas. Las personas que no conocen este método a veces pasan por formas complicadas de evitar el problema, como iterar a través de una copia.
No es terriblemente difícil hacer este genérico, por lo que funcionará en más que solo colecciones de Strings
, pero sin funciones de primera clase, no puede reemplazar el predicado (la condición dentro de if
), por lo que este código tiende a copiarse, pegarse y modificarse ligeramente.
Combina funciones de primera clase que te dan la habilidad para pasar el predicado como un parámetro, con la restricción de inmutabilidad que lo hace muy molesto si no lo haces, y obtienes bloques de construcción simples como filter
, como en este código de Scala que hace lo mismo:
list filter (!_.isEmpty)
Ahora piense en lo que el sistema de tipos verifica en su caso, en el momento de la compilación en el caso de Scala, pero estas comprobaciones también las realizan los sistemas de tipos dinámicos la primera vez que lo ejecuta:
-
list
debe ser algún tipo de tipo que admita el método filter
, es decir, una colección.
- Los elementos de
list
deben tener un método isEmpty
que devuelve un valor booleano.
- La salida será una colección (potencialmente) más pequeña con el mismo tipo de elementos.
Una vez que se han comprobado esas cosas, ¿qué otras formas quedan para que el programador las arruine? Accidentalmente olvidé el !
, lo que causó una falla de prueba extremadamente obvia. Ese es prácticamente el único error que se puede cometer, y solo lo hice porque estaba traduciendo directamente del código que probó la condición inversa.
Este patrón se repite una y otra vez. Las funciones de primera clase le permiten refactorizar las cosas en pequeñas utilidades reutilizables con una semántica precisa, restricciones como la inmutabilidad le dan el ímpetu para hacerlo, y la verificación de los parámetros de esas utilidades deja poco espacio para arruinarlas.
Por supuesto, todo esto depende de que el programador sepa que la función de simplificación como filter
ya existe, y de poder encontrarla, o de reconocer el beneficio de crear uno. Intente implementar esto usted mismo en todas partes utilizando solo la recursión de cola, y está de vuelta en el mismo barco de complejidad que la versión imperativa, pero peor. Solo porque puedas escribirlo de manera muy simple, no significa que la versión simple sea obvia.