Una versión de Go tiene a los desarrolladores de Go discutiendo sobre qué es Go siquiera, y admito que estoy disfrutando de las vistas desde nuestro lado de la valla. Go 1.27 trae métodos genéricos, un motor JSON reescrito deslizado bajo la API antigua, UUIDs en la biblioteca estándar, SIMD portable experimental, firmas post-cuánticas ML-DSA, rutas de asignación más baratas para objetos de menos de 80 bytes y detección en tiempo de ejecución de goroutines que nunca volverán a despertar. Y llega la ansiedad: ¿el lenguaje que construyó su marca a base de decir que no ha empezado por fin a decir que sí? Creo que la ansiedad apunta al blanco equivocado. La simplicidad nunca fue una propiedad de la ficha técnica. Vive en el diff que tu colega revisa un martes por la tarde, y con esa vara un lenguaje puede tener unas tripas enormemente complicadas y seguir siendo simple donde importa. PHP entendió esto hace años, casi por accidente, y Go 1.27 me suena a una admisión formal de que íbamos por buen camino.
Mira primero el cambio de JSON, porque es el movimiento más al estilo PHP de toda la versión. Go ahora tiene encoding/json/v2 con valores por defecto más estrictos y más configuración, pero el viejo encoding/json sigue funcionando porque ahora corre sobre la maquinaria nueva, con una vía de escape si la transición rompe algo. Import antiguo, motor nuevo. Nosotros hemos vivido exactamente esto. PHP 7 reemplazó las entrañas del Zend Engine, reelaboró los zvals y las hashtables, y la mayoría de las bases de código se actualizaron cambiando una etiqueta de Docker. PHP 8.0 atornilló un JIT a opcache y tus controladores ni se enteraron ni les importó. Nadie se levantó en una conferencia a acusar a PHP de traicionar el minimalismo, porque nadie confundió jamás el motor de PHP con un artefacto minimalista. El trato siempre fue que el núcleo hace el trabajo feo para que el userland siga siendo aburrido, y un userland aburrido es justamente la gracia del asunto.
Los métodos genéricos son el caso más difícil, y quiero ser justo con quienes están nerviosos. Un método que puede introducir sus propios parámetros de tipo, independientes de su receptor, no es fontanería del motor. Aparece en la revisión de código. Hace que los tipos Result con un Map que transforma en un Result parametrizado de otra manera se sientan como código normal, y una vez que eso se siente normal, vienen los pipelines tipados fluidos, luego las APIs de builder, luego diseños de librería importados de Rust y Kotlin. El argumento más fuerte contra las características expresivas nunca fue que sean inútiles. Es que cambian lo que tus compañeros usan por defecto, y el estilo por defecto de un equipo es mucho más difícil de revisar que cualquier función ingeniosa suelta. Ese argumento merece respeto. He visto una base de código en Laravel donde un autor de macros entusiasta redefinió en silencio lo que significaba idiomático para todos los demás del equipo.
Y aun así me pongo del lado de las adiciones, en parte por cómo las valló Go. Los métodos de interfaz no pueden declarar sus propios parámetros de tipo en 1.27, y los métodos genéricos no pueden satisfacer contratos de interfaz, lo que significa que el nuevo poder existe pero no puede propagarse por el canal principal de abstracción del lenguaje. Eso es racionamiento, y el racionamiento funciona. PHP ejecuta a diario una versión del mismo experimento: tenemos genéricos en la práctica mediante anotaciones en docblocks, con PHPStan o Psalm haciéndolas cumplir y cero soporte en tiempo de ejecución. Es incómodo, es una tregua más que un diseño, pero el colapso anunciado en sopa de abstracciones nunca llegó. Los equipos que querían colecciones tipadas las consiguieron. Los que no, siguieron escribiendo arrays. Las herramientas cargaron con la complejidad para que el motor no tuviera que hacerlo, que es solo otra respuesta a la misma pregunta de quién sostiene el saco.
La historia de los UUID en la stdlib es donde los dos ecosistemas divergen de verdad, y aquí estoy menos seguro de quién tiene razón. Go metió los UUIDs en la biblioteca estándar y luego tuvo que dar a database/sql un conocimiento especial del nuevo tipo para que se lleve bien con las conversiones de base de datos, una verruga que va contra el espíritu de las interfaces pequeñas. PHP fue por el camino contrario: el núcleo nunca incluyó UUIDs, y ramsey/uuid junto con symfony/uid se convirtieron en estándares de facto vía Composer. Nuestro enfoque mantiene limpio el núcleo y empuja la decisión a cada proyecto. El suyo bendice una implementación y acepta una mancha arquitectónica para hacerla ergonómica. He tecleado composer require ramsey/uuid tantas veces que mis dedos lo hacen sin supervisión, y todavía no sabría decirte si eso es libertad o solo un impuesto que dejé de notar.
A lo que sí pondría objeciones es al marco de la pendiente resbaladiza, la idea de que un lenguaje que aprende a absorber complejidad seguirá absorbiendo hasta convertirse en aquello de lo que huía. La acumulación es real, claro. Pero la barandilla no es la negativa, es una regla legible sobre dónde se le permite vivir a la complejidad. La regla implícita de PHP ha aguantado mejor de lo que le reconocemos: gasta sin miedo bajo la superficie, en opcache y el JIT y el preloading y la capa de FFI, y sé tacaño con la sintaxis que cambia el aspecto del código medio. Los enums, las propiedades readonly, la sintaxis de callables de primera clase, todo eso superó un listón alto y se ganó su sitio. El proceso de RFC es lento y a ratos exasperante, y también es la razón de que el código de PHP 8.4 todavía se lea como PHP para alguien que dejó el ecosistema en 2016.
Así que esto es lo que te preguntaría de verdad, porque el debate de Go es un ensayo de uno que nosotros seguimos aplazando. Si mañana aterrizara un RFC ofreciendo genéricos reificados de verdad en PHP, aplicados por el motor, sin docblocks, al precio de una complejidad interna seria y la casi certeza de que toda librería importante haría brotar APIs tipadas de builder y de pipeline en dos años, ¿votarías que sí? ¿O la tregua actual, con el análisis estático haciendo el trabajo de los genéricos mientras el runtime se mantiene al margen, es en secreto la mejor versión de colocación de la complejidad que podríamos haber diseñado a propósito? Yo cambio de opinión cada semana. Dime dónde te posicionas, y dime cómo se vería tu base de código tres años después de cualquiera de las dos respuestas.
Comentarios
Aún no hay comentarios — escribe el primero.
Inicia la conversación
Sin cuenta ni contraseña — introduce tu correo y te enviamos un enlace de acceso de un solo uso. ¿Primera vez? Todo se configura automáticamente.
Tu valoración se aplicará automáticamente al iniciar sesión.
Revisa tu bandeja de entrada
Hemos enviado un enlace de acceso a …. Ábrelo en este dispositivo — esta pestaña te conectará automáticamente.
¿No llega nada? Mira en la carpeta de spam — y marca el correo como «No es spam» para que la próxima vez llegue directo.