EL LENGUAJE DE LOS CIEN AÑOS
Abril 2003
(Este ensayo se deriva de una presentación en PyCon 2003.)
Es difícil predecir como será la vida dentro de cien años. Sólo hay unas pocas cosas que podemos mencionar con certeza. Sabemos que todo el mundo conducirá coches voladores, que las leyes de zonificación se relajaran para permitir edificios de cientos de pisos de altura, que estará oscuro la mayor parte del tiempo, y que todas las mujeres estarán entrenadas en artes marciales. Aquí quisiera enfocarme en un detalle de esta visión. ¿Qué tipo de lenguaje de programación usaran para escribir el software que controlara esos coches voladores?
Vale la pena considerar esto no tanto porque en realidad llegaremos a utilizar estos lenguajes, sino porque, si tenemos suerte, en el camino utilizaremos lenguajes desde este punto hasta ese.
Creo que, al igual que las especies, los lenguajes formarán árboles evolutivos, con callejones sin salida brotando por todas partes. Podemos ver que esto ya está sucediendo. Cobol, a pesar de su popularidad en algún momento, no parece tener ningún descendiente intelectual. Es un callejón sin salida evolutivo— un lenguaje Neanderthal.
Predigo un destino similar para Java. A veces la gente me envía correo diciendo: "¿Cómo puedes decir que Java no será un lenguaje exitoso? Ya es un lenguaje exitoso." Y admito que lo es, si mides el éxito por el espacio que ocupa en las estanterías los libros que tratan sobre el mismo (sobre todo los libros individuales que tratan sobre este), o por el número de estudiantes de licenciatura que creen que tienen que aprenderlo para conseguir un trabajo. Cuando digo que Java no será un lenguaje exitoso, me refiero a algo más específico: que Java resultara ser un callejón sin salida evolutivo, como Cobol.
Esta es sólo una conjetura. Puedo estar equivocado. Mi objetivo aquí no es ser irrespetuoso con Java, sino plantear la cuestión de los árboles evolutivos y hacer que la gente se pregunte ¿en qué parte del árbol esta el lenguaje X? La razón de esta pregunta no es sólo para que dentro de cien años nuestros fantasmas puedan decir: te lo dije. Es porque permanecer cerca de las ramas principales es una heurística útil para encontrar lenguajes que sean buenos para programar hoy.
En un momento dado, eres más feliz, probablemente, en las ramas principales de un árbol evolutivo. Aún cuando todavía había muchos Neandertales, debe haber sido un fastidio ser uno. Los Cro-Magnons habrían venido constantemente a golpearte y robarte la comida.
La razón por la que quiero saber como serán los lenguajes dentro de cien años es para saber a qué rama del árbol apostar ahora.
La evolución de los lenguajes se diferencía de la evolución de las especies, porque las ramas pueden converger. La rama de Fortran, por ejemplo, parece estar fusionándose con los descendientes de Algol. En teoría esto es posible para las especies también, pero no es probable que le haya ocurrido a algo más grande que una célula.
La convergencia es más probable para los lenguajes, en parte debido a que el espacio de posibilidades es menor, y en parte porque las mutaciones no son aleatorias. Los diseñadores de un lenguaje incorporan deliberadamente ideas de otros lenguajes.
Es especialmente útil para los diseñadores de lenguajes pensar hacia dónde llevara la evolución de los lenguajes de programación, para que pueden orientar el curso en consecuencia. En ese caso, "permanecer en una rama principal" se convierte en más que una manera 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 los axiomas, y el resto del lenguaje, que en principio podría ser escrito en términos de estos operadores fundamentales.
Creo que los operadores fundamentales son el factor más importante en la supervivencia a largo plazo de un lenguaje. El resto se puede cambiar. Es como la regla de que en la compra de una casa debes tener en cuenta la ubicación en primer lugar. Todo lo demás se puede arreglar más adelante, pero no puedes arreglar la ubicación.
Creo que es importante no sólo que los axiomas sean bien elegidos, sino que haya pocos de ellos. Los matemáticos siempre se han sentido así respecto a los axiomas —mientras menos, mejor— y creo que estan en lo cierto.
Por lo menos, tiene que ser un ejercicio útil observar de cerca el núcleo de un lenguaje para ver si hay axiomas que podrían eliminarse. En mi larga carrera de haragán he descubierto que el polvo engendra polvo, y he visto que esto sucede tanto en el software, como debajo de las camas y en las esquinas de las habitaciones. [a]
Tengo la corazonada de que las principales ramas del árbol evolutivo pasan a través de los lenguajes que tienen los núcleos más pequeños y limpios. Mientras más puedas escribir de un lenguaje en el mismo, mejor.
Por supuesto, estoy haciendo una gran suposición en preguntar incluso como serán los lenguajes de programación dentro de cien años. ¿Estaremos aún escribiendo programas en cien años? ¿No le diremos simplemente a las computadoras lo que queremos que hagan?
No ha habido mucho progreso en ese apartado hasta el momento. Mi conjetura es que en un centenar de años la gente todavía le dirá a las computadoras que hacer utilizando programas que se reconocerán como tales. Es posible que haya tareas que ahora resolvemos escribiendo programas y que en cien años no tendrás que escribir para resolverlas, pero creo que todavía habrá una buena cantidad de programación del tipo de la que hacemos hoy.
Puede parecer presuntuoso pensar que alguien pueda predecir como lucirá cualquier tecnología dentro de cien años. Pero recuerda que ya tenemos casi cincuenta años de historia a nuestras espaldas. Ver un centenar de años hacia el futuro es una idea comprensible si tenemos en cuenta la lentitud con que los lenguajes han evolucionado en los últimos cincuenta años.
Los lenguajes evolucionan lentamente porque no son realmente tecnologías. Los lenguajes son notación. Un programa es una descripción formal del problema que quieres que te resuelva una computadora. Por lo que la tasa de evolución de los lenguajes de programación se parece más a la tasa de evolución de la notación matemática que, digamos, al transporte o las comunicaciones. La notación matemática evoluciona, pero no a los gigantescos saltos que se ven en la tecnología.
Sin importar de que estén hechas las computadoras dentro de cien años, parece seguro predecir que serán mucho más rápidas de lo que son ahora. Si la Ley de Moore continúa haciéndose patente, serán 74 trillones (73,786,976,294,838,206,464) de veces más rápidas. Eso es un tanto difícil de imaginar. Y, en efecto, la predicción más probable en el apartado de la velocidad puede ser que la Ley de Moore dejará de funcionar. Cualquier cosa que se supone que se duplique cada dieciocho meses parece probable que se encuentre contra algún tipo de límite primordial eventualmente. Pero no tengo problemas para 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 debe cambiar considerablemente las reglas para los lenguajes de programación. Entre otras cosas, habrá más espacio para lo que ahora se consideran lenguajes lentos, es decir, lenguajes que no generan un código muy eficiente.
Y sin embargo, algunas aplicaciones todavía demandaran velocidad. Algunos de los problemas que queremos resolver con las computadoras son creados por las mismas; por ejemplo, la velocidad a la que tienes que procesar imágenes de vídeo depende de la velocidad a la que otra computadora las puede generar. Y hay otra clase de problemas que tienen inherentemente una capacidad ilimitada para absorber los 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 pueda ofrecer, una computadora más rápida significara que los lenguajes tienen que cubrir una gama cada vez más amplia de eficiencia. Hemos visto que esto ya está sucediendo. Las implementaciones actuales de algunos nuevos lenguajes populares son terriblemente derrochadoras comparadas con los estándares de décadas anteriores.
Esto no es sólo algo que ocurre con los lenguajes de programación. Se trata de una tendencia histórica general. Conforme las tecnologías mejoran, cada generación puede hacer cosas que la generación anterior hubiera considerado un desperdicio. La gente de hace treinta años se sorprendería de la forma tan casual con que hacemos llamadas de larga distancia. La gente hace cien años estaría aún más sorprendida de que un paquete viajaría un día de Boston a Nueva York pasando por Memphis.
Ya puedo decirte lo que le pasara a todos esos ciclos extra que un hardware más rápido nos dará en los próximos cien años. Casi todos se desperdiciaran.
Aprendí a programar cuando la potencia de las computadoras era escasa. Recuerdo eliminar todos los espacios de mis programas Basic para que encajaran en la memoria de un 4K TRS-80. La idea de todo este software estupendamente ineficiente quemando ciclos haciendo la misma cosa una y otra vez me parece un poco grosera. Pero creo que aquí mis intuiciones están equivocadas. Soy como alguien que creció en la pobreza, y no soporta gastar dinero aunque sea para algo importante, como ir al médico.
Algunos tipos de desperdicios son realmente repugnantes. Las SUVs, por ejemplo, podría decirse que serían groseras, aunque funcionaran con un combustible que nunca se agota y no generaran contaminación. Las SUVs son groseras porque son la solución a un problema grosero. (Cómo hacer que las minivans tengan un aspecto más masculino.) Pero no todo el desperdicio es malo. Ahora que tenemos la infraestructura de apoyo, contar los minutos de tus llamadas de larga distancia empieza a parecer insignificante. Si tienes los recursos, es más elegante pensar en todas las llamadas telefónicas como un tipo de cosa, sin importar donde esta la otra persona.
Hay desperdicio bueno, y desperdicio malo. Estoy interesado en el desperdicio bueno— del tipo que, al gastar más, podemos conseguir diseños más simples. ¿Cómo aprovecharemos las oportunidades para desperdiciar ciclos que obtendremos del nuevo hardware más rápido?
El deseo de velocidad esta tan profundamente arraigado en nosotros, con nuestras endebles computadoras, que tomará un esfuerzo consciente superarlo. En el diseño de lenguajes, debemos estar conscientemente buscando situaciones en las que se pueda cambiar la eficiencia por el más mínimo aumento de la comodidad.
La mayoría de las estructuras de datos existen debido a la velocidad. Por ejemplo, muchos lenguajes hoy en día tienen tanto cadenas como listas. Semánticamente, las cadenas son más o menos un subconjunto de las listas en las que los elementos son caracteres. ¿Entonces, por qué necesitas un tipo de datos separado? En realidad, no lo necesitas. Las cadenas sólo existen por eficiencia. Pero es poco original llenar la semántica del lenguaje con hacks para que los programas funcionen 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, sin duda es grosero tener axiomas adicionales que no añaden potencia expresiva, por el mero hecho de la eficiencia. La eficiencia es importante, pero no creo que ese sea el camino correcto para conseguirla.
La forma correcta de resolver el problema, creo yo, es separar lo que significa un programa de los detalles de su implementación. En lugar de tener tanto listas como cadenas, ten sólo listas, con alguna manera de dar al compilador recomendaciones de optimización que le permitan tender cadenas de bytes contiguos, si es necesario.
Puesto que la velocidad no importa en la mayor parte de un programa, normalmente no tendrás que 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.
Ser breve al explicar la implementación también debe hacer los programas más flexibles. Las especificaciones cambian mientras se escribe un programa y esto no es sólo inevitable, sino deseable.
La palabra "ensayo" proviene del verbo francés "essayer", que significa "intentar". Un ensayo, en el sentido original, es algo que escribes para intentar encontrar algo mejor. Esto sucede en el software también. Creo que algunos de los mejores programas fueron ensayos, en el sentido de que los autores no saben cuándo comenzó exactamente lo que estaban tratando de escribir.
Los hackers [b] de Lisp ya saben sobre el valor de ser flexible con las estructuras de datos. Tenemos la tendencia a escribir la primera versión de un programa de manera que haga todo con las listas. Estas versiones iniciales pueden ser tan terriblemente ineficientes que requiere un esfuerzo consciente no pensar en lo que están haciendo, así como, al menos para mí, comer un bistec requiere un esfuerzo consciente en no pensar de dónde viene.
Lo que los programadores dentro de cien años estarán buscando, sobre todo, es un lenguaje donde puedas crear una versión 1 increíblemente ineficiente de un programa con el menor esfuerzo posible. Al menos, así es como lo describimos en términos actuales. Lo qué dirán es que quieren un lenguaje en el que sea fácil programar.
El software ineficiente no es lo grave. Lo grave es un lenguaje que hace que los programadores hagan trabajo innecesario. Desperdiciar el tiempo del programador es la verdadera ineficiencia, no desperdiciar el tiempo de la máquina. Esto será cada vez más claro a medida que las computadoras se vuelvan más rápidas.
Creo que deshacerse de las cadenas es ya algo que podríamos soportar pensar. Lo hicimos en Arc, y parece ser una ganancia, algunas operaciones que serian difíciles describir como expresiones regulares pueden ser descritas fácilmente como funciones recursivas.
¿Hasta dónde llegará este aplanamiento de las estructuras de datos? Se me ocurren algunas posibilidades que me escandalizan incluso a mi, con todo y ser de amplio criterio. ¿Nos desharemos de las matrices, por ejemplo? Después de todo, son sólo un subconjunto de tablas hash donde las claves son vectores de números enteros. ¿Reemplazaremos las tablas hash con listas?
Hay perspectivas aún más chocantes que esas. El Lisp que McCarthy describió en 1960, por ejemplo, no tenia números. Lógicamente, no es necesario tener una noción separada de números, ya que pueden representarse como listas: el entero n puede ser representado como una lista de n elementos. Puedes hacer cálculos de esta manera. Es sólo que es insoportablemente ineficiente.
En realidad, en la práctica, nadie propuso implementar números como listas. De hecho, el articulo de 1960 de McCarthy no tenía, en ese momento, la intención de ser aplicado en absoluto. Fue un ejercicio teórico, un intento de crear una alternativa más elegante a la máquina de Turing. Cuando alguien, inesperadamente, tomó este articulo y lo tradujo a un intérprete de Lisp funcional, los números ciertamente no estaban representados como listas; estaban representados en el sistema binario, como en cualquier otro lenguaje.
¿Podría un lenguaje de programación ir tan lejos como para librarse de los números como un tipo de datos fundamental? Pregunto esto, no tanto como una cuestión seria, sino como una manera de afrontar el futuro. Es como el caso hipotético de una fuerza irresistible encontrándose con un objeto inamovible― aquí, una implementación increíblemente ineficiente encontrando recursos inimaginablemente grandes. No veo por qué no. El futuro es bastante extenso. Si hay algo que podamos hacer para disminuir el número de axiomas en el núcleo del lenguaje, parece ser el lado para apostar conforme t tiende a infinito. Si la idea aún parece insoportable dentro de cien años, tal vez no lo parecerá en un millar.
Para ser claros en esto, no estoy proponiendo que todos los cálculos numéricos en realidad se llevaran a cabo utilizando listas. Estoy proponiendo que el núcleo del lenguaje, previo a cualquier notación adicional sobre la implementación, sea definido de esta manera. En la práctica cualquier programa que quisiera hacer alguna cantidad de matemáticas probablemente representará los números en binario, pero esto sería una optimización, no parte de la semántica del núcleo del lenguaje.
Otra manera de quemar ciclos es tener muchas capas de software entre la aplicación y el hardware. Esta también es una tendencia que vemos que está sucediendo ya: muchos lenguajes recientes se compilan en byte code. Bill Woods, una vez me dijo que, como regla general, cada capa de interpretación cuesta un factor de 10 en la velocidad. Este costo extra te da flexibilidad.
La primera versión de Arc fue un caso extremo de este tipo de lentitud multinivel, con los consiguientes beneficios. Fue un clásico intérprete "metacircular" escrito sobre Common Lisp, con un definitivo aire de familia a la función eval definida en el artículo original de McCarthy sobre Lisp. El todo era sólo un par de cientos de líneas de código, así que era muy fácil de comprender y modificar. El Common Lisp que utilizamos, Clisp, se ejecuta sobre un intérprete de byte code. Así que aquí tenemos dos niveles de interpretación, uno de ellos (el superior) terriblemente ineficiente, pero el lenguaje es utilizable. Apenas utilizable, lo admito, pero utilizable.
Escribir software en forma de capas múltiples es una técnica potente incluso dentro de las aplicaciones. La programación de abajo-hacia arriba significa escribir un programa como una serie de capas, cada una de las cuales sirve como un lenguaje para la que esta sobre ella. Este enfoque tiende a producir programas flexibles más pequeños. Es también la mejor ruta a ese santo grial, la reutilización. Un lenguaje es, por definición, reutilizable. Cuanto más puedas forzar tu aplicación hacia un lenguaje para escribir ese tipo de aplicación, mayor cantidad de tu software será reutilizable.
De alguna manera, la idea de reutilización quedó unida a la programación orientada a objetos en la década de 1980, y ninguna cantidad de evidencia contraria parece ser capaz de liberarla. Pero aunque algo del software orientado a objetos es reutilizable, lo que lo hace reutilizable es su naturaleza orientada de abajo-hacia arriba, no su orientación a objetos. Considera las bibliotecas: son reutilizables porque son lenguaje, ya sea que estén escritas en un estilo orientado a objetos o no.
Por cierto, no predigo la desaparición de la programación orientada a objetos. Aunque no creo que tenga mucho que ofrecer a los buenos programadores, excepto en determinados ámbitos especializados, es irresistible para las grandes organizaciones. La programación orientada a objetos ofrece una manera sustentable de escribir código espagueti. Te permite acrecentar los programas como una serie de parches. Las grandes organizaciones siempre tienden a desarrollar software de esta manera, y creo que esto será tan cierto dentro de cien años como lo es hoy.
En tanto estemos hablando del futuro, sera mejor hablar de la computación en paralelo, porque ahí es donde esta idea parece residir. Es decir, no importa de cuando estés hablando, la computación en paralelo parece ser algo que sucederá en el futuro.
¿La alcanzará el futuro? La gente ha estado hablando de la computación paralela como algo inminente por al menos 20 años, y hasta ahora no ha afectado mucho a la práctica de la programación. ¿O no es así? Ya los diseñadores de chips tienen que pensar en ello, e igual la gente que trata de escribir software de sistema en computadoras con múltiples CPUs.
La verdadera pregunta es, ¿que tan alto llegara el paralelismo en la escalera de la abstracción? ¿Afectará dentro de cien años incluso a los programadores de aplicaciones? ¿O será algo en lo que pensaran los escritores 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 para el paralelismo se habrán de desperdiciar. Este es un caso especial de mi predicción más general de que la mayoría de la potencia adicional que nos darán las computadoras se desperdiciará. Espero que, al igual que con la estupenda velocidad del hardware subyacente, el paralelismo será algo que estará disponible si lo solicitas expresamente, pero que normalmente no se utilizará. Esto implica que el tipo de paralelismo que tendremos en cien años no será, salvo en ciertas aplicaciones, masivo. Espero que para los programadores ordinarios será más como poder empalmar procesos que terminaran todos corriendo en paralelo.
Y esto hará que, al igual que pedir implementaciones específicas de estructuras de datos, sea algo que hagas hasta más tarde en la vida de un programa, cuando tratas de optimizarlo. Las versiones 1 normalmente ignorarán cualquier ventaja que se pueda obtener de la computación en paralelo, del mismo modo que ignorarán las ventajas que se puedan obtener de representaciones de datos específicas.
Excepto en tipos especiales de aplicaciones, el paralelismo no impregnará los programas que sean escritos en un centenar de años. Sería optimización prematura si lo hicieran.
¿Cuántos lenguajes de programación habrá dentro de cien años? Parece haber un gran número de lenguajes de programación nuevos últimamente. Parte de la razón es que el hardware más rápido le ha permitido a los programadores hacer diferentes concesiones entre velocidad y conveniencia, dependiendo de la aplicación. Si esta es una tendencia real, el hardware que tendremos dentro de cien años no hara más que aumentarla.
Y sin embargo, puede que en cien años sólo haya unos pocos lenguajes ampliamente utilizados. Parte de la razón por la que digo esto es optimismo: parece que, si hiciste un trabajo realmente bueno, podrías hacer un lenguaje que era ideal para escribir una versión lenta 1, y sin embargo, con la adecuada sugerencia de optimización para el compilador, también arrojará código muy rápido cuando sea necesario. Por lo tanto, ya que soy optimista, voy a predecir que, a pesar de la enorme brecha que tendrán entre eficiencia máxima y aceptable, los programadores dentro de cien años tendrán lenguajes que pueden abarcar la mayor parte de ella.
A medida que esta brecha se amplía, los perfiladores serán cada vez más importantes. Se presta poca atención al perfilado ahora. Mucha gente todavía parece creer que la manera de conseguir aplicaciones rápidas es escribir compiladores que generen código rápido. A medida que la brecha entre desempeño aceptable y máximo se amplíe, será cada vez más claro que la forma de obtener aplicaciones rápidas es tener una buena guía de una a la otra.
Cuando digo que puede que sólo haya unos pocos lenguajes, no estoy incluyendo “lenguajes pequeños” de dominio específico. Creo que tales lenguajes integrados son una gran idea, y espero que proliferen. Pero espero que sean escritos como pieles suficientemente delgadas para que los usuarios puedan ver el lenguaje de propósito general por debajo.
¿Quién diseñará el lenguaje del futuro? Una de las tendencias más interesantes en los últimos diez años ha sido el aumento de lenguajes de código abierto como Perl, Python y Ruby. El diseño de lenguajes esta siendo asumido por los hackers. Los resultados hasta ahora son desordenados, pero alentadores. Hay algunas ideas increíblemente novedosas en Perl, por ejemplo. Muchas son increíblemente malas, pero eso siempre es cierto de los esfuerzos ambiciosos. A su actual tasa de mutación, sabrá Dios en lo que podría convertirse Perl en cien años.
No es verdad que aquellos que no pueden hacer, enseñan (algunos de los mejores hackers que conozco son profesores), pero es cierto que hay muchas cosas que los que enseñan no pueden hacer. La investigación impone limitantes restricciones de casta. En cualquier ámbito académico hay temas que son aceptables para trabajar y otros que no lo son. Por desgracia, la distinción entre los temas aceptables y prohibidos se basa generalmente en que tan intelectual suena el trabajo cuando se describe en los artículos de investigación, en lugar de que tan importante es para obtener buenos resultados. El caso extremo es, probablemente, la literatura; la gente que estudia literatura raramente dice algo que pueda ser de la menor utilidad para aquellos que la producen.
Aunque la situación es mejor en las ciencias, la coincidencia entre el tipo de trabajo que se te permite hacer y el tipo de trabajo que produce buenos lenguajes es preocupantemente pequeño. (Olin Shivers se quejó con elocuencia acerca de esto) Por ejemplo, los tipos parecen ser una fuente inagotable de trabajos de investigación, a pesar de que el tipado estático parece excluir las verdaderas macros― sin las cuales, en mi opinión, no vale la pena usar ningún lenguaje.
La tendencia no es sólo hacia lenguajes que están siendo desarrollados como proyectos de código abierto en lugar de "investigación", sino hacia lenguajes siendo diseñados por los programadores de aplicaciones que necesitan usarlos, en lugar de por los escritores de compiladores. Esta parece una tendencia positiva y espero que continúe.
A diferencia de la física dentro de cien años, que es casi por necesidad imposible de predecir, creo que puede ser posible, en principio, diseñar un lenguaje hoy que sea atractivo a 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 hardware que pueda ejecutarlo. Cuando haces esto puedes suponer recursos ilimitados. Parece que debemos ser capaces de imaginar recursos ilimitados, tanto hoy como dentro de cien años.
¿Qué programa querría escribir uno? El que cueste menos trabajo. Excepto no exactamente: cualquiera que fuera menos trabajo si tus ideas acerca de la programación no se vieron afectadas ya por los lenguajes a los que actualmente estas acostumbrado. Esta influencia puede ser tan penetrante que se necesita un gran esfuerzo para superarla. Se podría pensar que sería obvio para criaturas tan flojas como nosotros la forma de expresar un programa con el mínimo esfuerzo. De hecho, nuestras ideas acerca de lo que es posible tiende a estar tan limitada por cualquier lenguaje en el que pensamos que formulaciones mas sencillas de programas parecen muy sorprendentes. Son algo que tienes que descubrir, no algo en lo que te pones a trabajar.
Un truco útil en este caso es utilizar la longitud del programa como una aproximación a cuanto trabajo es escribir. No la longitud en caracteres, por supuesto, sino la longitud de distintos elementos sintácticos― básicamente, el tamaño del árbol de análisis. Puede que no sea del todo cierto que el programa más corto es el que da menos trabajo escribir, pero esta tan cerca que te ira mejor apuntando al sólido blanco de la brevedad que al difuso y cercano, de menor trabajo. Entonces, el algoritmo para el diseño de lenguajes se convierte en: Observa un programa y pregunta, ¿hay alguna manera de escribir esto que sea más corta?
En la práctica, escribir programas en un imaginario lenguaje de cien años funciona a diferentes grados dependiendo de que tan cerca estés al núcleo. Clasifica las rutinas que puedas escribir ahora. Pero sería difícil predecir qué tipo de bibliotecas podrían necesitarse en un centenar de años. Es de suponer que muchas bibliotecas serán para dominios que no existen todavía. Si SETI@home funciona, por ejemplo, vamos a necesitar bibliotecas para comunicarnos con los extraterrestres. A menos que, por supuesto, estén lo suficientemente avanzados que ya se comunican en XML.
En el otro extremo, creo que podrías ser capaz de diseñar el núcleo del lenguaje en la actualidad. De hecho, algunos podrían argumentar que ya estaba casi todo diseñado en 1958.
Si el lenguaje de los cien años estuviera disponible hoy en día, ¿querríamos programar en él? Una forma de responder a esta pregunta es mirar hacia atrás. Si los lenguajes de programación de hoy en día hubieran estado disponibles en 1960, ¿alguien habría querido utilizarlos?
En cierta forma, la respuesta es no. Los lenguajes de hoy en día asumen infraestructura que no existía en 1960. Por ejemplo, un lenguaje en el que las sangrías son importantes como Python, no iba a funcionar muy bien en las terminales de las impresoras. Pero dejando a un lado este tipo de problemas ―asumiendo, por ejemplo, que los programas sólo estuvieran escritos en papel― ¿Le hubiera gustado a los programadores de la década de 1960 escribir programas en los lenguajes que usamos hoy día?
Creo que sí. Algunos de los menos imaginativos, que tuvieran residuos de lenguajes tempranos incorporados en sus ideas de lo que era un programa, podrían haber tenido problemas. (¿Cómo se pueden manipular los datos sin tener que hacer aritmética de punteros? ¿Cómo se pueden implementar diagramas de flujo, sin gotos?) Pero creo que los programadores más inteligentes no hubieran tenido problemas para sacar el máximo partido de los lenguajes de hoy en día, si los hubieran tenido.
Si tuviéramos el lenguaje de los cien años ahora, por lo menos haría un gran pseudocódigo. ¿Qué tal usarlo para escribir software? Dado que el lenguaje de los cien años tendrá que generar código rápido para algunas aplicaciones, es de suponer que podría generar código lo suficientemente eficiente para funcionar aceptablemente bien en nuestro hardware. Puede que tengamos que dar más recomendaciones de optimización que usuarios dentro de cien años, pero aún podría ser una ganancia neta.
Ahora tenemos dos ideas que, si se combinan, sugieren interesantes posibilidades: (1) el lenguaje de los cien años podría, en principio, ser diseñado hoy en día, y (2) tal lenguaje, si existiera, podría ser bueno para programar en la actualidad. Cuando ves estas ideas expuestas así, es difícil no pensar, ¿por qué no intentar escribir el lenguaje de los cien años ahora?
Cuando estás trabajando en el diseño de lenguajes, creo que es bueno tener ese objetivo y mantenerlo conscientemente en la mente. Cuando se aprende a conducir, uno de los principios que te enseñan es no alinear el auto empatando el cofre contra las rayas pintadas en el camino, sino apuntando a algún sitio en la distancia. Incluso si lo único que 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 en encarnar el principio de que las declaraciones (excepto las de las variables dinámicas) no eran más que recomendaciones de optimización, y no cambiaría el significado de un programa correcto. Common Lisp parece haber sido el primero en declarar esto de manera explícita.
Gracias a Trevor Blackwell, Robert Morris, y Dan Giffin por leer borradores de esto y a Guido van Rossum, Jeremy Hylton, y el resto del equipo de Python por haberme invitado a hablar en PyCon.
Notas del Traductor
[a] Juego de palabras. El vocablo que utiliza en inglés para describir el polvo es cruft, utilizado en el argot informatico significa código malo, pero es también el polvo que se acumula bajo las camas.
[b] En La Palabra "Hacker" Paul Graham nos da una buena descripción del sentido en que hay que entender esta palabra: “Para la prensa popular, "hacker" significa alguien que irrumpe en las computadoras. Entre los programadores significa: un buen programador. Pero los dos sentidos están conectados. Para los programadores, "hacker" connota dominio en el sentido más literal: alguien que puede hacer que una computadora haga lo que él quiere—ya sea que la computadora quiera o no.”