Durante los últimos años aparecieron innumerables artículos anunciando la muerte del polimorfismo. La llegada de sealed classes, union types y pattern matching hizo que muchos comenzaran a tratar la orientación a objetos como una técnica del pasado.
Sin embargo, las críticas al polimorfismo no son nuevas. Tampoco las críticas al pattern matching. De hecho, muchas de ellas fueron formuladas por las personas que diseñaron estos paradigmas mucho antes de que existieran Java, Kotlin o Rust.
Vale la pena volver a esas discusiones:
Agregar operaciones es difícil
Philip Wadler formuló en 1998 el famoso Expression Problem.
Su observación sigue siendo una de las críticas más fuertes al polimorfismo: los sistemas orientados a objetos hacen muy sencillo incorporar nuevos tipos, pero extremadamente costoso agregar nuevas operaciones.
Cada nueva operación obliga a modificar toda la jerarquía de clases.
Desde esta perspectiva, el pattern matching invierte completamente el problema: agregar una operación suele consistir simplemente en escribir una nueva función.
No es casualidad que muchos desarrolladores funcionales vean al patrón Visitor como una consecuencia directa de esta limitación.
El comportamiento queda disperso
Martin Odersky ha defendido repetidamente el pattern matching como una herramienta para expresar algoritmos completos en un único lugar.
Cuando la lógica está distribuida entre decenas de implementaciones distintas, comprender una operación completa implica recorrer buena parte del proyecto.
Con pattern matching, el algoritmo aparece concentrado y resulta mucho más sencillo razonar sobre él.
La pregunta implícita es incómoda para la orientación a objetos: ¿Queremos organizar el código alrededor de los datos o alrededor de las operaciones?
El despacho dinámico oculta demasiado
Otra crítica frecuente desde el mundo funcional es que el polimorfismo sacrifica legibilidad en favor de la extensibilidad.
Una llamada aparentemente inocente puede terminar ejecutando cualquiera de decenas de implementaciones.
El flujo del programa deja de ser evidente y pasa a depender de la jerarquía de tipos.
Para muchos, el pattern matching hace exactamente lo contrario: vuelve explícitas todas las alternativas posibles.
Pattern Matching rompe el encapsulamiento
Si hubiera que elegir una crítica histórica, probablemente sea la de Alan Kay.
Kay insistió durante décadas en que los objetos nunca fueron concebidos como estructuras de datos con comportamiento, sino como entidades que colaboran mediante el envío de mensajes.
Desde esa mirada, inspeccionar explícitamente el estado de un objeto para decidir qué hacer significa abandonar el modelo de objetos y volver a programar sobre representaciones internas.
No es una cuestión sintáctica.
Es un cambio de filosofía.
Cada nuevo tipo obliga a revisar todos los matches
Bertrand Meyer, creador de Eiffel y autor del principio Open/Closed, probablemente encontraría aquí su principal objeción.
Cuando aparece un nuevo subtipo, todos los matches relevantes deben ser revisados.
La lógica que antes estaba distribuida vuelve a concentrarse en múltiples lugares.
El costo del cambio deja de estar en agregar operaciones y pasa a estar en agregar variantes del modelo.
Exactamente el problema inverso al planteado por Wadler.
Un match de 500 líneas sigue siendo un switch de 500 líneas
Quizás sea la crítica más práctica.
El pattern matching no garantiza buen diseño.
Nada impide escribir enormes bloques de decisiones difíciles de mantener.
Cambiar la sintaxis de switch por match no elimina automáticamente el acoplamiento ni mejora la modularidad.
Muchas veces simplemente produce un switch más elegante.
Entonces... ¿quién tiene razón?
Probablemente ambos.
Philip Wadler demostró que la orientación a objetos favorece la extensión por tipos.
Bertrand Meyer mostró que esa misma decisión permite mantener el sistema cerrado frente a modificaciones cuando aparecen nuevos comportamientos internos.
Alan Kay defendió durante toda su carrera que los objetos deberían ocultar completamente su representación.
Martin Odersky respondió que muchas veces entender un algoritmo completo es más importante que esconder la representación de los datos.
No son respuestas contradictorias.
Responden preguntas diferentes.
Cada cierto tiempo la industria intenta declarar un ganador.
Hace veinte años parecía que todo debía resolverse con herencia y polimorfismo.
Hoy pareciera que todo debería resolverse con pattern matching.
La realidad es bastante menos interesante para quienes buscan una respuesta definitiva: ninguno reemplaza al otro.
Uno optimiza la evolución del sistema cuando aparecen nuevos tipos.
El otro optimiza la evolución cuando aparecen nuevas operaciones.
No existe una técnica superior.
Existe una pregunta mucho más importante:
¿Qué es lo que cambia con mayor frecuencia en tu dominio?
Porque esa respuesta, mucho más que el paradigma elegido, suele determinar cuál de las dos herramientas encaja mejor.

No hay comentarios.:
Publicar un comentario