GoSuda

Comparación del diseño de lenguajes en entornos de generación de código con LLM: costo de abstracción y explicitud de Go

By Rabbit Princess views ...

Lenguajes modernos

Un lenguaje moderno se refiere a un lenguaje que ofrece mayor productividad, estabilidad, seguridad y mantenibilidad en comparación con los lenguajes del pasado. Estos lenguajes incorporan de manera activa técnicas y conceptos recientes, y ofrecen a los desarrolladores herramientas de desarrollo más eficientes y seguras. Entre los lenguajes modernos representativos se encuentran Java, Rust, Python y TypeScript, entre otros, y presentan las siguientes características.

1. Diseño orientado a objetos ( OOP )

Los lenguajes modernos se diseñan, en su mayoría, a partir de conceptos de programación orientada a objetos. La orientación a objetos admite principios como la encapsulación, la herencia y el polimorfismo, y al dividir un sistema complejo en objetos de unidades pequeñas para su gestión, da a la estructura del programa claridad y flexibilidad. Esto resulta especialmente eficaz en el desarrollo de software a gran escala, ya que permite controlar los costos y el esfuerzo de desarrollo y reducir los problemas que pueden surgir durante el mantenimiento.

2. Azúcar sintáctica y expresiones

Los lenguajes modernos ofrecen diversas azúcares sintácticas y gramáticas basadas en expresiones para mejorar la legibilidad del código y la productividad del desarrollo. Funciones como el operador ternario, las expresiones lambda y la coincidencia de patrones reducen el código repetitivo, hacen el código predecible y aumentan la productividad del desarrollador.

3. Sistema de módulos

Los lenguajes modernos permiten separar un programa en múltiples unidades mediante un sistema de módulos. Esto facilita la reutilización del código y la gestión de dependencias, y hace que el mantenimiento resulte manejable incluso cuando el tamaño del proyecto crece. Como ejemplos representativos se encuentran Maven/Gradle en Java, Cargo en Rust y npm/yarn en TypeScript.

4. Lenguajes intermedios y máquinas virtuales

Los lenguajes modernos incorporan lenguajes intermedios y máquinas virtuales para lograr independencia de plataforma, optimización del rendimiento y seguridad. Como ejemplos representativos se encuentran JVM, LLVM, WASM y GraalVM.

Desarrollo en la era de la IA y las limitaciones de los lenguajes modernos

Los lenguajes modernos surgieron bajo la premisa de que las personas escriben la mayor parte del código. Naturalmente, el propósito de los lenguajes modernos es reducir el trabajo repetitivo, aumentar la productividad y, mediante estructuras que permiten la colaboración entre desarrolladores, implementar de manera eficaz software de gran escala. Sin embargo, en la era de la IA esta premisa se derrumba gradualmente. Herramientas basadas en IA como Copilot y Cody automatizan gran parte de la escritura de código, y la cantidad de código que puede producir una sola persona desarrolladora aumenta de forma notable. Como resultado, las características de los lenguajes modernos que antes se percibían como ventajas se están convirtiendo gradualmente en desventajas propias de una época pasada.

Diseño orientado a objetos

La IA puede analizar de forma rápida y precisa una estructura en la que toda la información está explícita dentro de una sola función o módulo. Por el contrario, a medida que aumenta el contexto, crece el espacio de inferencia, por lo que la productividad y la precisión de la IA disminuyen. El código escrito con OOP tiende a distribuir la lógica entre múltiples objetos en lugar de gestionarla en un solo lugar, lo que, en consecuencia, exige a la IA más contexto. Observe el siguiente código.

 1public class AnimalHandler {
 2    public void handle(Animal animal) {
 3        animal.speak();
 4    }
 5}
 6
 7public class Main {
 8    public static void main(String[] args) {
 9        AnimalHandler handler = new AnimalHandler();
10
11        Animal a1 = new Dog();
12        Animal a2 = new Cat();
13        Animal a3 = new Horse();
14
15        handler.handle(a1);
16        handler.handle(a2);
17        handler.handle(a3);
18    }
19}

En el código anterior, para saber qué operación realiza realmente el método speak(), la IA debe repetir el siguiente razonamiento

  1. ¿De qué clase concreta es instancia animal?
  2. ¿Dónde está definido el método speak() sobrescrito en esa clase?
  3. ¿Dónde están las definiciones de las clases Dog y Cat, y cuál es su comportamiento interno?
  4. ¿Existe la posibilidad de que las clases Dog y Cat sean sobrescritas en otras clases?

Esta información no se encuentra reunida en un solo archivo o función, sino que solo puede comprenderse siguiendo las relaciones entre los archivos de clases y la estructura de herencia. Además, los elementos que se determinan en tiempo de ejecución, como la reflexión o la carga dinámica, son para la IA como una caja negra, por lo que su análisis es prácticamente imposible.

Azúcar sintáctica y expresiones

La IA prefiere el comportamiento explícito frente al implícito, y en lugar de utilizar estructuras complejas, prefiere combinar estructuras simples para construir una única respuesta correcta. En cambio, la azúcar sintáctica permite diversas formas de expresión, pero su comportamiento interno suele ser idéntico o similar. La IA debe aprender el significado de cada una de estas expresiones una por una, y puede resultarle difícil determinar qué gramática recomendar en cada situación concreta según su prioridad.

Lenguajes intermedios y máquinas virtuales

La IA aprende principalmente a partir del código fuente. En cambio, el lenguaje intermedio (bytecode) elimina durante la compilación significados como los nombres de las variables, y la máquina virtual debe reinterpretarlo en el momento de la ejecución. Esta es una tarea muy difícil de comprender o transformar para la IA. Por ejemplo, para la IA es posible convertir TypeScript a Go, pero convertir el bytecode del motor V8 al bytecode de la JVM o a código máquina es prácticamente imposible.

El verdadero lenguaje moderno para la era de la IA

A partir de lo anterior, podemos observar que las características de los lenguajes modernos son, en realidad, elementos anticuados poco adecuados para la era de la IA. Entonces, ¿qué lenguaje podría ser el más adecuado como lenguaje moderno para la era de la IA? Una pista puede encontrarse en los elementos que los lenguajes modernos del pasado rechazaron. Un lenguaje moderno para la era de la IA debe:

  1. Tener una sintaxis explícita y un flujo natural.
  2. Alejarse de las estructuras orientadas a objetos excesivas y tener una estructura plana y simple.
  3. En lugar de azúcar sintáctica innecesaria o patrones implícitos, construir múltiples funciones únicamente con un conjunto limitado de palabras clave básicas.
  4. Tener un sistema de compilación simple y predecible, en lugar de un sistema de compilación complejo.

El lenguaje que mejor cumple con estos criterios es Golang. El lenguaje Go está diseñado para implementar la mayoría de las funciones prácticas usando únicamente un conjunto mínimo de palabras clave centrales y una combinación sencilla de sintaxis, y excluye rigurosamente las abstracciones innecesarias y el comportamiento implícito. Esto resulta ventajoso tanto para los desarrolladores como para que la IA interprete y genere código.

De este modo, las características de Go, que apuntan a una estructura predecible y plana, un flujo explícito y una sintaxis coherente, encajan mejor en un entorno de desarrollo en el que la IA participa activamente, a diferencia de los lenguajes modernos existentes, diseñados con el desarrollador humano como referencia. La filosofía de diseño conservadora de Go, que en otro tiempo se consideró anticuada, se convierte, de hecho, en la opción más avanzada en la era de la IA.