EL LENGUAJE DE LOS CIEN AÑOS
OriginalAbril de 2003
(Este ensayo se deriva de una charla magistral en PyCon 2003.)
Es difícil predecir cómo será la vida dentro de cien años. Sólo hay unas pocas cosas que podemos decir con certeza. Sabemos que todo el mundo conducirá coches voladores, que las leyes de zonificación se relajarán para permitir edificios de cientos de pisos, que estará oscuro la mayor parte del tiempo y que todas las mujeres serán entrenadas en artes marciales. Aquí quiero centrarme en un detalle de esta imagen: ¿qué tipo de lenguaje de programación utilizarán para escribir el software que controle esos coches voladores?
Vale la pena pensar en esto, no tanto porque realmente usaremos estos idiomas, sino porque, si tenemos suerte, los usaremos en el camino desde este punto hasta aquel.
Creo que, al igual que las especies, los idiomas formarán árboles evolutivos, con ramificaciones sin salida por todas partes. Ya podemos ver que esto está sucediendo. El COBOL, a pesar de su popularidad, no parece tener descendientes intelectuales. Es un callejón sin salida evolutivo, un lenguaje neandertal.
Predico un destino similar para Java. A veces me envían mensajes diciendo: "¿Cómo puedes decir que Java no se convertirá en un lenguaje exitoso? Ya es un lenguaje exitoso". Y admito que lo es, si se mide el éxito por el espacio que ocupan los libros sobre él (en particular, los libros individuales sobre él) o por la cantidad de estudiantes universitarios que creen que tienen que aprenderlo para conseguir un trabajo. Cuando digo que Java no se convertirá en un lenguaje exitoso, me refiero a algo más específico: que Java se convertirá en un callejón sin salida evolutivo, como Cobol.
Esto es sólo una suposición. Puede que me equivoque. Mi objetivo aquí no es criticar Java, sino plantear la cuestión de los árboles evolutivos y hacer que la gente se pregunte: ¿en qué parte del árbol se encuentra el lenguaje X? La razón para hacer esta pregunta no es sólo para que nuestros fantasmas puedan decir: en cien años, te lo dije. Es porque permanecer cerca de las ramas principales es una heurística útil para encontrar lenguajes en los que será bueno programar ahora.
En cualquier momento, probablemente te sientas más feliz en las ramas principales de un árbol evolutivo. Incluso cuando todavía había muchos neandertales, debe haber sido una pesadilla ser uno de ellos. Los cromañones se acercaban constantemente para golpearte y robarte la comida.
La razón por la que quiero saber cómo serán los idiomas dentro de cien años es para saber en qué rama del árbol apostar ahora.
La evolución de los lenguajes difiere de la evolución de las especies porque las ramas pueden converger. La rama Fortran, por ejemplo, parece estar fusionándose con los descendientes de Algol. En teoría, esto también es posible para las especies, pero no es probable que haya sucedido con ningún organismo más grande que una célula.
La convergencia es más probable en el caso de los lenguajes, en parte porque el espacio de posibilidades es menor y en parte porque las mutaciones no son aleatorias. Los diseñadores de lenguajes incorporan deliberadamente ideas de otros lenguajes.
Resulta especialmente útil para los diseñadores de lenguajes pensar en el rumbo que probablemente tomará la evolución de los lenguajes de programación, ya que pueden orientarse en consecuencia. En ese caso, "permanecer en una rama principal" se convierte en algo más que una forma de elegir un buen lenguaje. Se convierte en una heurística para tomar las decisiones correctas sobre el diseño de lenguajes.
Cualquier lenguaje de programación se puede dividir en dos partes: un conjunto de operadores fundamentales que desempeñan el papel de axiomas, y el resto del lenguaje, que en principio podría escribirse en términos de estos operadores fundamentales.
Creo que los operadores fundamentales son el factor más importante para la supervivencia a largo plazo de un idioma. El resto se puede cambiar. Es como la regla de que, al comprar una casa, hay que tener en cuenta la ubicación en primer lugar. Todo lo demás se puede arreglar más adelante, pero no se puede arreglar la ubicación.
Creo que es importante no sólo que los axiomas estén bien elegidos, sino que sean pocos. Los matemáticos siempre han pensado así sobre los axiomas (cuanto menos, mejor) y creo que están en lo cierto.
Como mínimo, debe ser un ejercicio útil observar de cerca el núcleo de un lenguaje para ver si hay axiomas que se puedan eliminar. En mi larga carrera como vago he descubierto que la basura genera basura, y he visto que esto sucede tanto en el software como debajo de las camas y en los rincones de las habitaciones.
Tengo la corazonada de que las ramas principales del árbol evolutivo pasan por los lenguajes que tienen los núcleos más pequeños y limpios. Cuanto más se pueda escribir sobre un lenguaje, mejor.
Por supuesto, estoy haciendo una gran suposición al preguntar cómo serán los lenguajes de programación dentro de cien años. ¿Estaremos siquiera escribiendo programas dentro de cien años? ¿No les diremos simplemente a las computadoras lo que queremos que hagan?
Hasta ahora no ha habido muchos avances en ese aspecto. Supongo que dentro de cien años la gente seguirá diciéndoles a las computadoras qué hacer mediante programas que reconoceríamos como tales. Puede que haya tareas que resolvamos ahora escribiendo programas y que dentro de cien años no será necesario escribir programas para resolverlas, pero creo que seguirá habiendo una buena cantidad de programación del tipo que hacemos hoy.
Puede parecer presuntuoso pensar que alguien puede predecir cómo será cualquier tecnología dentro de cien años, pero recuerde que ya tenemos casi cincuenta años de historia a nuestras espaldas. Mirar hacia adelante cien años es una idea comprensible si consideramos lo lento que han evolucionado los idiomas en los últimos cincuenta.
Los lenguajes evolucionan lentamente porque en realidad no son tecnologías. Los lenguajes son notación. Un programa es una descripción formal del problema que quieres que resuelva un ordenador. Por tanto, la velocidad de evolución de los lenguajes de programación es más parecida a la de la notación matemática que, por ejemplo, la del transporte o las comunicaciones. La notación matemática evoluciona, pero no con los saltos gigantescos que se ven en la tecnología.
Sea cual sea el material del que estén hechas las computadoras dentro de cien años, parece seguro predecir que serán mucho más rápidas que ahora. Si la Ley de Moore sigue funcionando, serán 74 trillones (73.786.976.294.838.206.464) de veces más rápidas. Es algo difícil de imaginar. Y, de hecho, la predicción más probable en el departamento de velocidad puede ser que la Ley de Moore deje de funcionar. Todo lo que se supone que se duplica cada dieciocho meses parece probable que se tope con algún tipo de límite fundamental en algún momento. Pero no tengo ningún problema en creer que las computadoras serán mucho más rápidas. Incluso si sólo terminan siendo un mísero millón de veces más rápidas, eso debería cambiar sustancialmente las reglas básicas para los lenguajes de programación. Entre otras cosas, habrá más espacio para lo que ahora se considerarían lenguajes lentos, es decir, lenguajes que no producen código muy eficiente.
Y, sin embargo, algunas aplicaciones seguirán exigiendo velocidad. Algunos de los problemas que queremos resolver con ordenadores son creados por los ordenadores; por ejemplo, la velocidad a la que hay que procesar imágenes de vídeo depende de la velocidad a la que otro ordenador pueda generarlas. Y hay otra clase de problemas que tienen inherentemente una capacidad ilimitada para absorber ciclos: la representación de imágenes, la criptografía, las simulaciones.
Si algunas aplicaciones pueden ser cada vez más ineficientes mientras que otras siguen exigiendo toda la velocidad que el hardware puede ofrecer, las computadoras más rápidas significarán que los lenguajes tendrán que cubrir una gama cada vez más amplia de eficiencias. Ya hemos visto que esto sucede. Las implementaciones actuales de algunos lenguajes nuevos y populares son sorprendentemente derrochadoras en comparación con los estándares de décadas anteriores.
Esto no es algo que sólo ocurre con los lenguajes de programación, sino una tendencia histórica general. A medida que las tecnologías mejoran, cada generación puede hacer cosas que la generación anterior habría considerado un desperdicio. Hace treinta años, la gente se sorprendería de la facilidad con la que hacemos llamadas telefónicas de larga distancia. Hace cien años, la gente se sorprendería aún más de que un día un paquete viajara de Boston a Nueva York vía Memphis.
Ya puedo adelantarles lo que va a pasar con todos esos ciclos adicionales que nos va a proporcionar el hardware más rápido en los próximos cien años. Casi todos se van a desperdiciar.
Aprendí a programar cuando la potencia informática era escasa. Recuerdo que quitaba todos los espacios de mis programas de Basic para que cupieran en la memoria de una TRS-80 4K. La idea de que todo ese software tremendamente ineficiente queme ciclos haciendo lo mismo una y otra vez me parece un poco desagradable. Pero creo que mis intuiciones en este sentido son erróneas. Soy como alguien que creció pobre y no soporta gastar dinero ni siquiera en algo importante, como ir al médico.
Algunos tipos de residuos son realmente repugnantes. Los todoterrenos, por ejemplo, serían asquerosos incluso si funcionaran con un combustible que nunca se agotaría y no generaría contaminación. Los todoterrenos son asquerosos porque son la solución a un problema asqueroso (cómo hacer que las minivans parezcan más masculinas). Pero no todos los residuos son malos. Ahora que tenemos la infraestructura para respaldarlos, contar los minutos de las llamadas de larga distancia comienza a parecer una molestia. Si tienes los recursos, es más elegante pensar en todas las llamadas telefónicas como un solo tipo de cosa, sin importar dónde esté la otra persona.
Hay desperdicios buenos y malos. Me interesa el desperdicio bueno, el que se produce cuando, gastando más, podemos obtener diseños más simples. ¿Cómo aprovecharemos las oportunidades de desperdiciar ciclos que nos brindará el nuevo hardware más rápido?
El deseo de velocidad está tan arraigado en nosotros, con nuestras pequeñas computadoras, que será necesario un esfuerzo consciente para superarlo. En el diseño de lenguajes, deberíamos buscar conscientemente situaciones en las que podamos sacrificar eficiencia por incluso el más mínimo aumento en comodidad.
La mayoría de las estructuras de datos existen por su velocidad. Por ejemplo, muchos lenguajes actuales tienen cadenas y listas. Semánticamente, las cadenas son más o menos un subconjunto de listas en las que los elementos son caracteres. Entonces, ¿por qué se necesita un tipo de datos independiente? En realidad, no es necesario. Las cadenas solo existen por eficiencia, pero es una tontería saturar la semántica del lenguaje con trucos para que los programas se ejecuten más rápido. Tener cadenas en un lenguaje parece ser un caso de optimización prematura.
Si pensamos en el núcleo de un lenguaje como un conjunto de axiomas, seguramente es repugnante tener axiomas adicionales que no añaden poder expresivo, simplemente por el bien de la eficiencia. La eficiencia es importante, pero no creo que sea la forma correcta de lograrla.
Creo que la forma correcta de resolver ese problema es separar el significado de un programa de los detalles de implementación. En lugar de tener tanto listas como cadenas, es mejor tener solo listas, con alguna forma de brindarle al compilador consejos de optimización que le permitan disponer las cadenas como bytes contiguos si es necesario.
Como la velocidad no es importante en la mayoría de los programas, normalmente no necesitarás preocuparte por este tipo de microgestión. Esto será cada vez más cierto a medida que las computadoras se vuelvan más rápidas.
Menos detalles sobre la implementación también deberían hacer que los programas sean más flexibles. Las especificaciones cambian mientras se escribe un programa, y esto no solo es inevitable, sino deseable.
La palabra "ensayo" proviene del verbo francés "essayer", que significa "intentar". Un ensayo, en el sentido original, es algo que se escribe para intentar descifrar algo. Esto también ocurre en el software. Creo que algunos de los mejores programas eran ensayos, en el sentido de que los autores no sabían exactamente lo que estaban tratando de escribir cuando empezaron.
Los hackers de Lisp ya conocen el valor de ser flexibles con las estructuras de datos. Tendemos a escribir la primera versión de un programa de forma que haga todo con listas. Estas versiones iniciales pueden ser tan sorprendentemente ineficientes que se requiere un esfuerzo consciente para no pensar en lo que están haciendo, de la misma manera que, al menos para mí, comer un filete requiere un esfuerzo consciente para no pensar de dónde viene.
Lo que buscarán los programadores dentro de cien años es, sobre todo, un lenguaje en el que se pueda crear una versión 1 de un programa increíblemente ineficiente con el mínimo esfuerzo posible. Al menos, así es como lo describiríamos en términos actuales. Lo que dirán es que quieren un lenguaje en el que sea fácil programar.
El software ineficiente no es desagradable. Lo desagradable es un lenguaje que obliga a los programadores a realizar un trabajo innecesario. La verdadera ineficiencia es perder el tiempo de los programadores, no perder el tiempo de las máquinas. Esto se hará cada vez más evidente a medida que las computadoras se vuelvan más rápidas.
Creo que deshacernos de las cadenas es algo que ya podríamos considerar. Lo hicimos en Arc y parece ser un éxito; algunas operaciones que serían difíciles de describir como expresiones regulares se pueden describir fácilmente como funciones recursivas.
¿Hasta dónde llegará esta simplificación de las estructuras de datos? Se me ocurren posibilidades que me sorprenderían incluso a mí, que tengo una mente más abierta y consciente. ¿Nos desharemos de las matrices, por ejemplo? Después de todo, son solo un subconjunto de las tablas hash donde las claves son vectores de números enteros. ¿Reemplazaremos las propias tablas hash por listas?
Hay perspectivas aún más impactantes que esa. El Lisp que McCarthy describió en 1960, por ejemplo, no tenía números. Lógicamente, no es necesario tener una noción separada de números, porque se pueden representar como listas: el entero n se puede representar como una lista de n elementos. Se pueden hacer matemáticas de esta manera. Es simplemente insoportablemente ineficiente.
En realidad, nadie propuso implementar números como listas en la práctica. De hecho, el artículo de McCarthy de 1960 no estaba pensado para implementarse en ese momento. Era un ejercicio teórico , un intento de crear una alternativa más elegante a la máquina de Turing. Cuando alguien, inesperadamente, tomó este artículo y lo tradujo a un intérprete Lisp funcional, los números ciertamente no se representaban como listas; se representaban en binario, como en cualquier otro lenguaje.
¿Podría un lenguaje de programación llegar tan lejos como para deshacerse de los números como tipo de datos fundamental? No hago esta pregunta como una forma de jugar a la gallina con el futuro. Es como el caso hipotético de una fuerza irresistible que se encuentra con un objeto inamovible; en este caso, una implementación inimaginablemente ineficiente se encuentra con recursos inimaginablemente grandes. No veo por qué no. El futuro es bastante largo. Si hay algo que podemos hacer para reducir el número de axiomas en el lenguaje central, ese parecería ser el lado al que apostar a medida que t se acerca al infinito. Si la idea todavía parece insoportable en cien años, tal vez no lo sea en mil.
Para que quede claro, no estoy proponiendo que todos los cálculos numéricos se realicen utilizando listas. Propongo que el lenguaje central, antes de cualquier notación adicional sobre la implementación, se defina de esta manera. En la práctica, cualquier programa que quisiera hacer cualquier cantidad de operaciones matemáticas probablemente representaría números en binario, pero esto sería una optimización, no parte de la semántica del lenguaje central.
Otra forma de quemar ciclos es tener muchas capas de software entre la aplicación y el hardware. Esta también es una tendencia que ya estamos viendo: muchos lenguajes recientes se compilan en código de bytes. Bill Woods me dijo una vez que, como regla general, cada capa de interpretación cuesta un factor de 10 en velocidad. Este costo adicional te permite ganar flexibilidad.
La primera versión de Arc fue un caso extremo de este tipo de lentitud de varios niveles, con sus correspondientes beneficios. Era un intérprete "metacircular" clásico escrito sobre Common Lisp, con un parecido familiar definido con la función eval definida en el artículo original de McCarthy sobre Lisp. Todo el conjunto consistía en sólo un par de cientos de líneas de código, por lo que era muy fácil de entender y modificar. El Common Lisp que utilizábamos, CLisp, se ejecutaba sobre un intérprete de código de bytes. Así que aquí teníamos dos niveles de interpretación, uno de ellos (el superior) sorprendentemente ineficiente, y el lenguaje era utilizable. Apenas utilizable, lo admito, pero utilizable.
Escribir software en múltiples capas es una técnica poderosa incluso dentro de las aplicaciones. La programación ascendente significa escribir un programa en una serie de capas, cada una de las cuales sirve como lenguaje para la capa superior. Este enfoque tiende a generar programas más pequeños y flexibles. También es la mejor ruta hacia ese santo grial, la reutilización. Un lenguaje es, por definición, reutilizable. Cuanto más de su aplicación pueda incluir en un lenguaje para escribir ese tipo de aplicación, más de su software será reutilizable.
De alguna manera, la idea de reutilización se adhirió a la programación orientada a objetos en la década de 1980, y ninguna cantidad de evidencia en contra parece poder deshacerse de ella. Pero aunque algunos programas orientados a objetos son reutilizables, lo que los hace reutilizables es su carácter de abajo hacia arriba, no su orientación a objetos. Consideremos las bibliotecas: son reutilizables porque son lenguaje, ya sea que estén escritas en un estilo orientado a objetos o no.
Por cierto, no preveo la desaparición de la programación orientada a objetos. Aunque no creo que tenga mucho que ofrecer a los buenos programadores, excepto en ciertos dominios especializados, es irresistible para las grandes organizaciones. La programación orientada a objetos ofrece una forma sostenible de escribir código espagueti. Permite acumular programas como una serie de parches.
Las grandes organizaciones siempre tienden a desarrollar software de esta manera, y espero que en cien años esto sea tan cierto como lo es hoy.
Ya que hablamos del futuro, es mejor que hablemos de computación paralela, porque ahí es donde parece estar arraigada esta idea. Es decir, no importa cuándo hablemos, la computación paralela parece ser algo que va a suceder en el futuro.
¿Se alcanzará alguna vez el futuro? La gente lleva hablando de computación paralela como algo inminente al menos desde hace 20 años, y hasta ahora no ha afectado mucho a la práctica de la programación. ¿O no? Los diseñadores de chips ya tienen que pensar en ello, y también deben hacerlo quienes intentan escribir software de sistemas en ordenadores con múltiples CPU.
La verdadera pregunta es: ¿hasta dónde llegará el paralelismo en la escala de abstracción? ¿Dentro de cien años afectará incluso a los programadores de aplicaciones? ¿O será algo en lo que pensarán los desarrolladores de compiladores, pero que suele ser invisible en el código fuente de las aplicaciones?
Una cosa que parece probable es que la mayoría de las oportunidades de paralelismo se desperdicien. Este es un caso especial de mi predicción más general de que la mayor parte de la potencia informática adicional que se nos da se desperdiciará. Espero que, al igual que con la estupenda velocidad del hardware subyacente, el paralelismo sea algo que esté disponible si lo solicitas explícitamente, pero que normalmente no se use. Esto implica que el tipo de paralelismo que tendremos dentro de cien años no será, excepto en aplicaciones especiales, un paralelismo masivo. Espero que para los programadores comunes sea más como poder bifurcar procesos que terminen ejecutándose todos en paralelo.
Y esto, al igual que pedir implementaciones específicas de estructuras de datos, será algo que se hará bastante tarde en la vida de un programa, cuando se intente optimizarlo. Las versiones 1 normalmente ignorarán las ventajas que se pueden obtener de la computación paralela, de la misma manera que ignorarán las ventajas que se pueden obtener de representaciones específicas de datos.
Salvo en casos especiales de aplicación, el paralelismo no se extenderá a los programas que se escriban dentro de cien años. Sería una optimización prematura si así fuera.
¿Cuántos lenguajes de programación habrá dentro de cien años? Últimamente parece haber una enorme cantidad de lenguajes de programación nuevos. Parte de la razón es que el hardware más rápido ha permitido a los programadores hacer diferentes concesiones entre velocidad y conveniencia, según la aplicación. Si esta es una tendencia real, el hardware que tendremos dentro de cien años debería aumentarla.
Y, sin embargo, puede que dentro de cien años sólo haya unos pocos lenguajes ampliamente utilizados. En parte, digo esto por optimismo: parece que, si se hiciera un buen trabajo, se podría crear un lenguaje que fuera ideal para escribir una versión 1 lenta y, sin embargo, con el asesoramiento de optimización adecuado para el compilador, también se podría producir código muy rápido cuando fuera necesario. Así que, como soy optimista, voy a predecir que, a pesar de la enorme brecha que habrá entre la eficiencia aceptable y la máxima, los programadores dentro de cien años tendrán lenguajes que puedan abarcar la mayor parte de esa eficiencia.
A medida que esta brecha se amplíe, los perfiladores serán cada vez más importantes. Actualmente se presta poca atención a la creación de perfiles. Mucha gente parece seguir creyendo que la forma de obtener aplicaciones rápidas es escribir compiladores que generen código rápido. A medida que se amplíe la brecha entre el rendimiento aceptable y el máximo, quedará cada vez más claro que la forma de obtener aplicaciones rápidas es tener una buena guía para pasar de uno a otro.
Cuando digo que puede que solo haya unos pocos idiomas, no estoy incluyendo los "pequeños idiomas" específicos de un dominio. Creo que esos idiomas integrados son una gran idea y espero que proliferen. Pero espero que estén escritos como capas lo suficientemente delgadas como para que los usuarios puedan ver el lenguaje de uso general que hay debajo.
¿Quién diseñará los lenguajes del futuro? Una de las tendencias más emocionantes de los últimos diez años ha sido el auge de los lenguajes de código abierto como Perl, Python y Ruby. Los hackers están asumiendo el control del diseño de lenguajes. Los resultados hasta ahora son confusos, pero alentadores. Hay algunas ideas sorprendentemente novedosas en Perl, por ejemplo. Muchas son sorprendentemente malas, pero eso siempre es cierto en el caso de los esfuerzos ambiciosos. Al ritmo actual de mutación, Dios sabe en qué podría evolucionar Perl dentro de cien años.
No es cierto que quienes no pueden hacer, enseñen (algunos de los mejores hackers que conozco son profesores), pero sí es cierto que hay muchas cosas que quienes enseñan no pueden hacer. La investigación impone restricciones de casta restrictivas. En cualquier campo académico hay temas en los que se puede trabajar y otros en los que no. Desafortunadamente, la distinción entre temas aceptables y prohibidos suele basarse en lo intelectual que suena el trabajo cuando se describe en los artículos de investigación, en lugar de en lo importante que es para obtener buenos resultados. El caso extremo es probablemente la literatura; la gente que estudia literatura rara vez dice algo que pueda ser de la más mínima utilidad para quienes la producen.
Aunque la situación es mejor en las ciencias, la superposición entre el tipo de trabajo que se permite hacer y el tipo de trabajo que produce buenos lenguajes es angustiosamente pequeña. (Olin Shivers se ha quejado elocuentemente sobre esto.) Por ejemplo, los tipos parecen ser una fuente inagotable de artículos de investigación, a pesar del hecho de que la tipificación estática parece excluir las macros verdaderas, sin las cuales, en mi opinión, no vale la pena usar ningún lenguaje.
La tendencia no es simplemente que los lenguajes se desarrollen como proyectos de código abierto en lugar de como "investigación", sino que los lenguajes sean diseñados por los programadores de aplicaciones que necesitan usarlos, en lugar de por los escritores de compiladores. Esta parece una buena tendencia y espero que continúe.
A diferencia de lo que sucederá en física dentro de cien años, que es casi necesariamente imposible de predecir, creo que en principio puede ser posible diseñar un lenguaje ahora que resulte atractivo para los usuarios dentro de cien años.
Una forma de diseñar un lenguaje es simplemente escribir el programa que te gustaría poder escribir, independientemente de si existe un compilador que pueda traducirlo o un hardware que pueda ejecutarlo. Cuando haces esto, puedes suponer que los recursos son ilimitados. Parece que deberíamos poder imaginar recursos ilimitados tanto hoy como dentro de cien años.
¿Qué programa le gustaría escribir a uno? Cualquiera que requiera menos trabajo. Excepto que no exactamente: cualquier cosa que requiera menos trabajo si sus ideas sobre programación no estuvieran ya influenciadas por los lenguajes a los que está acostumbrado actualmente. Tal influencia puede ser tan penetrante que requiere un gran esfuerzo superarla. Uno pensaría que sería obvio para criaturas tan perezosas como nosotros cómo expresar un programa con el mínimo esfuerzo. De hecho, nuestras ideas sobre lo que es posible tienden a estar tan limitadas por el lenguaje en el que pensamos que las formulaciones más fáciles de los programas parecen muy sorprendentes. Son algo que uno tiene que descubrir, no algo en lo que uno se sumerge naturalmente.
Un truco útil en este caso es utilizar la longitud del programa como una aproximación de cuánto trabajo es escribirlo. No la longitud en caracteres, por supuesto, sino la longitud en elementos sintácticos distintos; básicamente, el tamaño del árbol de análisis. Puede que no sea del todo cierto que el programa más corto sea el que menos trabajo requiere, pero es lo suficientemente cercano como para que sea mejor apuntar al objetivo sólido de brevedad en lugar del objetivo difuso y cercano de menos trabajo. Entonces el algoritmo para el diseño de lenguajes se convierte en: mira un programa y pregúntate: ¿hay alguna manera de escribirlo que sea más corto?
En la práctica, escribir programas en un lenguaje imaginario de cien años funcionará en distintos grados dependiendo de lo cerca que esté del núcleo. Las rutinas de clasificación se pueden escribir ahora, pero sería difícil predecir ahora qué tipo de bibliotecas podrían necesitarse dentro de cien años. Es de suponer que muchas bibliotecas serán para dominios que ni siquiera existen todavía. Si SETI@home funciona, por ejemplo, necesitaremos bibliotecas para comunicarnos con extraterrestres, a menos, por supuesto, que sean lo suficientemente avanzadas como para comunicarse ya en XML.
En el otro extremo, creo que hoy en día se podría diseñar el lenguaje básico. De hecho, algunos podrían argumentar que ya estaba diseñado en su mayor parte en 1958.
Si el lenguaje de hace cien años estuviera disponible hoy, ¿querríamos programar en él? Una forma de responder a esta pregunta es mirar atrás. Si los lenguajes de programación actuales hubieran estado disponibles en 1960, ¿alguien habría querido utilizarlos?
En cierto modo, la respuesta es no. Los lenguajes actuales presuponen una infraestructura que no existía en 1960. Por ejemplo, un lenguaje en el que la sangría es importante, como Python, no funcionaría muy bien en terminales de impresora. Pero dejando de lado esos problemas (suponiendo, por ejemplo, que los programas se escribieran todos en papel), ¿les habría gustado a los programadores de la década de 1960 escribir programas en los lenguajes que utilizamos hoy?
Creo que sí. Algunos de los menos imaginativos, que tenían artefactos de lenguajes antiguos incorporados a sus ideas de lo que era un programa, podrían haber tenido problemas. (¿Cómo se pueden manipular datos sin hacer aritmética de punteros? ¿Cómo se pueden implementar diagramas de flujo sin gotos?) Pero creo que los programadores más inteligentes no habrían tenido problemas para aprovechar al máximo los lenguajes actuales, si los hubieran tenido.
Si tuviéramos el lenguaje de hace cien años ahora, al menos sería un pseudocódigo excelente. ¿Qué tal si lo usáramos para escribir software? Dado que el lenguaje de hace cien años necesitará generar código rápido para algunas aplicaciones, presumiblemente podría generar código lo suficientemente eficiente como para funcionar aceptablemente bien en nuestro hardware. Tal vez tengamos que dar más consejos de optimización que los usuarios dentro de cien años, pero aún así podría ser una ganancia neta.
Ahora tenemos dos ideas que, si las combinamos, sugieren posibilidades interesantes: (1) el lenguaje de los cien años podría, en principio, diseñarse hoy, y (2) un lenguaje así, si existiera, podría ser bueno para programar hoy. Cuando vemos estas ideas expuestas de esa manera, es difícil no pensar: ¿por qué no intentar escribir el lenguaje de los cien años ahora?
Cuando se trabaja en el diseño de lenguajes, creo que es bueno tener un objetivo de este tipo y mantenerlo conscientemente en mente. Cuando aprendes a conducir, uno de los principios que te enseñan es alinear el coche no alineando el capó con las rayas pintadas en la carretera, sino apuntando a algún punto en la distancia. Incluso si lo único que te importa es lo que sucede en los próximos tres metros, esta es la respuesta correcta. Creo que podemos y debemos hacer lo mismo con los lenguajes de programación.
Notas
Creo que Lisp Machine Lisp fue el primer lenguaje que incorporó el principio de que las declaraciones (excepto las de variables dinámicas) eran meros consejos de optimización y no cambiarían el significado de un programa correcto. Common Lisp parece haber sido el primero en afirmarlo explícitamente.
Gracias a Trevor Blackwell, Robert Morris y Dan Giffin por leer borradores de este documento, y a Guido van Rossum, Jeremy Hylton y el resto del equipo de Python por invitarme a hablar en PyCon.