SER POPULAR
OriginalMayo de 2001
(Este artículo fue escrito como una especie de plan de negocios para un nuevo lenguaje . Por eso, le falta (porque da por sentado) la característica más importante de un buen lenguaje de programación: abstracciones muy potentes.)
Un amigo mío le dijo una vez a un eminente experto en sistemas operativos que quería diseñar un lenguaje de programación realmente bueno. El experto le respondió que sería una pérdida de tiempo, que los lenguajes de programación no se vuelven populares o impopulares en función de sus méritos y que, por muy bueno que fuera su lenguaje, nadie lo usaría. Al menos, eso era lo que había sucedido con el lenguaje que él había diseñado.
¿Qué hace que un lenguaje sea popular? ¿Los lenguajes populares merecen su popularidad? ¿Vale la pena intentar definir un buen lenguaje de programación? ¿Cómo lo harías?
Creo que las respuestas a estas preguntas se pueden encontrar observando a los hackers y aprendiendo lo que quieren. Los lenguajes de programación son para los hackers, y un lenguaje de programación es bueno como lenguaje de programación (en lugar de, por ejemplo, un ejercicio de semántica denotacional o diseño de compiladores) si y solo si a los hackers les gusta.
1 La mecánica de la popularidad
Es cierto, sin duda, que la mayoría de la gente no elige lenguajes de programación basándose simplemente en sus méritos. A la mayoría de los programadores alguien les dice qué lenguaje utilizar. Y, sin embargo, creo que el efecto de estos factores externos en la popularidad de los lenguajes de programación no es tan grande como a veces se cree. Creo que un problema mayor es que la idea que tiene un hacker de un buen lenguaje de programación no es la misma que la que tienen la mayoría de los diseñadores de lenguajes.
Entre los dos, la opinión del hacker es la que importa. Los lenguajes de programación no son teoremas, son herramientas diseñadas para personas, y deben ser diseñadas para adaptarse a las fortalezas y debilidades humanas, tanto como los zapatos deben ser diseñados para los pies humanos. Si un zapato aprieta al ponérselo, es un zapato malo, por elegante que sea como pieza de escultura.
Puede ser que la mayoría de los programadores no sepan distinguir un lenguaje bueno de uno malo, pero eso no es diferente con cualquier otra herramienta. No significa que sea una pérdida de tiempo intentar diseñar un buen lenguaje. Los hackers expertos pueden distinguir un buen lenguaje cuando lo ven, y lo usarán. Los hackers expertos son una pequeña minoría, hay que reconocerlo, pero esa pequeña minoría escribe todo el buen software, y su influencia es tal que el resto de los programadores tenderá a usar el lenguaje que ellos usen. A menudo, de hecho, no se trata simplemente de influencia sino de mando: a menudo los hackers expertos son las mismas personas que, como sus jefes o asesores de la facultad, les dicen a los demás programadores qué lenguaje usar.
La opinión de los hackers expertos no es la única fuerza que determina la popularidad relativa de los lenguajes de programación (el software heredado (Cobol) y la moda (Ada, Java) también juegan un papel), pero creo que es la fuerza más poderosa a largo plazo. Si se le da una masa crítica inicial y suficiente tiempo, un lenguaje de programación probablemente se vuelva tan popular como se merece. Y la popularidad separa aún más a los buenos lenguajes de los malos, porque la retroalimentación de los usuarios reales siempre conduce a mejoras. Observe cuánto ha cambiado cualquier lenguaje popular a lo largo de su vida. Perl y Fortran son casos extremos, pero incluso Lisp ha cambiado mucho. Lisp 1.5 no tenía macros, por ejemplo; éstas evolucionaron más tarde, después de que los hackers del MIT pasaran un par de años usando Lisp para escribir programas reales. [1]
Así que, independientemente de si un lenguaje tiene que ser bueno o no para ser popular, creo que un lenguaje tiene que ser popular para ser bueno. Y tiene que seguir siendo popular para seguir siendo bueno. El estado del arte en los lenguajes de programación no se detiene. Y, sin embargo, los Lisp que tenemos hoy siguen siendo bastante parecidos a los que había en el MIT a mediados de los años 80, porque esa fue la última vez que Lisp tuvo una base de usuarios lo suficientemente grande y exigente.
Por supuesto, los hackers tienen que conocer un lenguaje antes de poder usarlo. ¿Cómo van a enterarse? De otros hackers. Pero tiene que haber un grupo inicial de hackers que use el lenguaje para que otros se enteren. Me pregunto qué tan grande tiene que ser este grupo; ¿cuántos usuarios forman una masa crítica? De memoria, diría veinte. Si un lenguaje tuviera veinte usuarios diferentes, es decir, veinte usuarios que decidieran por su cuenta usarlo, lo consideraría real.
Llegar a ese punto no debe ser fácil. No me sorprendería que fuera más difícil pasar de cero a veinte que de veinte a mil. La mejor manera de conseguir esos veinte usuarios iniciales es probablemente utilizar un caballo de Troya: darles a las personas una aplicación que quieran, que esté escrita en el nuevo lenguaje.
2 Factores externos
Comencemos por reconocer un factor externo que sí afecta la popularidad de un lenguaje de programación. Para ser popular, un lenguaje de programación tiene que ser el lenguaje de scripts de un sistema popular. Fortran y Cobol eran los lenguajes de scripts de los primeros mainframes de IBM. C era el lenguaje de scripts de Unix y, posteriormente, lo fue Perl. Tcl es el lenguaje de scripts de Tk. Java y Javascript están destinados a ser los lenguajes de scripts de los navegadores web.
Lisp no es un lenguaje muy popular porque no es el lenguaje de programación de un sistema muy popular. La popularidad que conserva se remonta a los años 1960 y 1970, cuando era el lenguaje de programación del MIT. Muchos de los grandes programadores de la época estuvieron asociados con el MIT en algún momento. Y a principios de los años 1970, antes de C, el dialecto de Lisp del MIT, llamado MacLisp, era uno de los únicos lenguajes de programación que un hacker serio querría usar.
Hoy en día Lisp es el lenguaje de programación de dos sistemas moderadamente populares, Emacs y Autocad, y por esa razón sospecho que la mayor parte de la programación Lisp que se hace hoy en día se hace en Emacs Lisp o AutoLisp.
Los lenguajes de programación no existen de forma aislada. Hackear es un verbo transitivo (los hackers suelen hackear algo) y, en la práctica, los lenguajes se juzgan en relación con aquello que se utiliza para hackear. Por lo tanto, si quieres diseñar un lenguaje popular, tienes que proporcionar más que un lenguaje o tienes que diseñar tu lenguaje para reemplazar el lenguaje de scripting de algún sistema existente.
Common Lisp es impopular en parte porque es huérfano. Originalmente venía con un sistema para hackear: la máquina Lisp. Pero las máquinas Lisp (junto con las computadoras paralelas) fueron aplastadas por la creciente potencia de los procesadores de propósito general en la década de 1980. Common Lisp podría haber seguido siendo popular si hubiera sido un buen lenguaje de programación para Unix. Lamentablemente, es un lenguaje atrozmente malo.
Una forma de describir esta situación es decir que un lenguaje no se juzga por sus propios méritos. Otra visión es que un lenguaje de programación no es realmente un lenguaje de programación a menos que también sea el lenguaje de scripting de algo. Esto sólo parece injusto si llega como una sorpresa. Creo que no es más injusto que esperar que un lenguaje de programación tenga, por ejemplo, una implementación. Es sólo parte de lo que es un lenguaje de programación.
Por supuesto, un lenguaje de programación necesita una buena implementación, y esta debe ser gratuita. Las empresas pagan por el software, pero los hackers individuales no, y son a los hackers a los que hay que atraer.
Un lenguaje también necesita un libro que lo trate. El libro debe ser breve, estar bien escrito y estar repleto de buenos ejemplos. K&R es el ideal en este caso. En este momento, casi diría que un lenguaje debe tener un libro publicado por O'Reilly. Esa se está convirtiendo en la prueba de que es importante para los hackers.
También debería haber documentación en línea. De hecho, el libro puede empezar como documentación en línea. Pero no creo que los libros físicos hayan pasado de moda todavía. Su formato es cómodo y la censura de facto impuesta por los editores es un filtro útil aunque imperfecto. Las librerías son uno de los lugares más importantes para aprender sobre nuevos idiomas.
3 Brevedad
Dado que puedes proporcionar las tres cosas que cualquier lenguaje necesita (una implementación gratuita, un libro y algo para hackear), ¿cómo creas un lenguaje que les guste a los hackers?
Una cosa que les gusta a los hackers es la brevedad. Los hackers son vagos, de la misma manera que lo son los matemáticos y los arquitectos modernistas: odian todo lo que sea superfluo. No estaría lejos de la verdad decir que un hacker que está a punto de escribir un programa decide qué lenguaje utilizar, al menos de manera inconsciente, en función del número total de caracteres que tendrá que escribir. Si no es así exactamente como piensan los hackers, un diseñador de lenguajes haría bien en actuar como si así fuera.
Es un error tratar de mimar al usuario con expresiones largas que pretenden parecerse al inglés. Cobol es conocido por esta falla. Un hacker consideraría que se le pidiera que escribiera
Sumar x a y da z
en lugar de
z = x+y
como algo entre un insulto a su inteligencia y un pecado contra Dios.
A veces se ha dicho que Lisp debería usar first y rest en lugar de car y cdr, porque haría que los programas fueran más fáciles de leer. Quizás durante las primeras horas. Pero un hacker puede aprender bastante rápido que car significa el primer elemento de una lista y cdr significa el resto. Usar first y rest significa escribir un 50% más. Y también tienen longitudes diferentes, lo que significa que los argumentos no se alinearán cuando se los llame, como sucede a menudo con car y cdr, en líneas sucesivas. He descubierto que importa mucho cómo se alinea el código en la página. Apenas puedo leer código Lisp cuando está configurado en una fuente de ancho variable, y mis amigos dicen que esto también es cierto para otros lenguajes.
La brevedad es un aspecto en el que los lenguajes fuertemente tipados pierden. En igualdad de condiciones, nadie quiere empezar un programa con un montón de declaraciones. Todo lo que pueda ser implícito, debería serlo.
Los tokens individuales también deberían ser cortos. Perl y Common Lisp ocupan polos opuestos en esta cuestión. Los programas Perl pueden ser casi crípticamente densos, mientras que los nombres de los operadores integrados de Common Lisp son cómicamente largos. Los diseñadores de Common Lisp probablemente esperaban que los usuarios tuvieran editores de texto que escribieran estos nombres largos por ellos. Pero el costo de un nombre largo no es solo el costo de escribirlo. También está el costo de leerlo y el costo del espacio que ocupa en la pantalla.
4. Hackeabilidad
Hay una cosa más importante para un hacker que la brevedad: poder hacer lo que uno quiere. En la historia de los lenguajes de programación se ha dedicado una cantidad sorprendente de esfuerzo a impedir que los programadores hagan cosas que se consideran inapropiadas. Se trata de un plan peligrosamente presuntuoso. ¿Cómo puede el diseñador del lenguaje saber lo que el programador va a tener que hacer? Creo que los diseñadores de lenguajes harían mejor en considerar que su usuario objetivo es un genio que tendrá que hacer cosas que nunca anticiparon, en lugar de un torpe que necesita ser protegido de sí mismo. El torpe se disparará en el pie de todos modos. Puede evitar que haga referencia a variables en otro paquete, pero no puede evitar que escriba un programa mal diseñado para resolver el problema equivocado y que tarde una eternidad en hacerlo.
Los buenos programadores a menudo quieren hacer cosas peligrosas y desagradables. Por desagradables me refiero a cosas que van más allá de la fachada semántica que el lenguaje intenta presentar: por ejemplo, hacerse con la representación interna de alguna abstracción de alto nivel. A los hackers les gusta hackear, y hackear significa meterse dentro de las cosas y cuestionar al diseñador original.
No dejes que te cuestionen. Cuando creas una herramienta, la gente la usa de maneras que no tenías previstas, y esto es especialmente cierto en el caso de una herramienta muy articulada como un lenguaje de programación. Muchos hackers querrán modificar tu modelo semántico de una manera que nunca imaginaste. Yo digo que lo hagan; dale al programador acceso a la mayor cantidad de información interna que puedas sin poner en peligro los sistemas de ejecución como el recolector de basura.
En Common Lisp, a menudo he deseado recorrer los campos de una estructura (para buscar referencias a un objeto eliminado, por ejemplo, o encontrar campos que no se hayan inicializado). Sé que las estructuras son solo vectores subyacentes, pero no puedo escribir una función de propósito general a la que pueda llamar en cualquier estructura. Solo puedo acceder a los campos por su nombre, porque eso es lo que se supone que significa una estructura.
Un hacker puede querer subvertir el modelo de cosas previsto sólo una o dos veces en un programa grande, pero qué diferencia supone poder hacerlo. Y puede que no se trate sólo de una cuestión de resolver un problema. También aquí hay una especie de placer. Los hackers comparten el placer secreto del cirujano al hurgar en las entrañas asquerosas, el placer secreto del adolescente al reventar granos. [2] Para los chicos, al menos, ciertos tipos de horrores son fascinantes. La revista Maxim publica un volumen anual de fotografías, que contiene una mezcla de chicas de revista y accidentes espeluznantes. Conocen a su público.
Históricamente, Lisp ha sido bueno en permitir que los hackers hagan lo que quieran. La corrección política de Common Lisp es una aberración. Los primeros Lisp permitían tener acceso a todo. Afortunadamente, buena parte de ese espíritu se conserva en las macros. Qué maravilloso poder hacer transformaciones arbitrarias en el código fuente.
Las macros clásicas son una auténtica herramienta de hackers: sencillas, potentes y peligrosas. Es muy fácil entender lo que hacen: llamas a una función en los argumentos de la macro y lo que devuelva se inserta en lugar de la llamada a la macro. Las macros higiénicas encarnan el principio opuesto. Intentan protegerte de que entiendas lo que están haciendo. Nunca he oído que se expliquen las macros higiénicas en una sola frase. Y son un ejemplo clásico de los peligros de decidir lo que los programadores pueden querer. Las macros higiénicas están pensadas para protegerme de la captura de variables, entre otras cosas, pero la captura de variables es exactamente lo que quiero en algunas macros.
Un lenguaje realmente bueno debe ser limpio y sucio a la vez: bien diseñado, con un núcleo pequeño de operadores bien comprendidos y altamente ortogonales, pero sucio en el sentido de que permite a los hackers hacer lo que quieran con él. C es así. Lo mismo ocurría con los primeros Lisp. Un lenguaje de verdadero hacker siempre tendrá un carácter ligeramente descuidado.
Un buen lenguaje de programación debería tener características que hagan que la clase de personas que usan la frase "ingeniería de software" sacudan la cabeza con desaprobación. En el otro extremo del espectro están lenguajes como Ada y Pascal, modelos de propiedad que son buenos para la enseñanza y no mucho más.
5 programas descartables
Para que resulte atractivo para los hackers, un lenguaje debe ser adecuado para escribir el tipo de programas que quieren escribir. Y eso significa, aunque parezca sorprendente, que tiene que ser adecuado para escribir programas desechables.
Un programa desechable es un programa que se escribe rápidamente para alguna tarea limitada: un programa para automatizar alguna tarea de administración del sistema, o generar datos de prueba para una simulación, o convertir datos de un formato a otro. Lo sorprendente de los programas desechables es que, al igual que los edificios "temporales" construidos en tantas universidades estadounidenses durante la Segunda Guerra Mundial, a menudo no se desechan. Muchos evolucionan hasta convertirse en programas reales, con funciones y usuarios reales.
Tengo la corazonada de que los mejores grandes programas comienzan así, en lugar de diseñarse a lo grande desde el principio, como la presa Hoover. Es aterrador construir algo grande desde cero. Cuando la gente emprende un proyecto demasiado grande, se siente abrumada. El proyecto o bien se estanca, o el resultado es estéril y acartonado: un centro comercial en lugar de un verdadero centro urbano, Brasilia en lugar de Roma, Ada en lugar de C.
Otra forma de conseguir un programa grande es empezar con un programa descartable y seguir mejorándolo. Este enfoque es menos desalentador y el diseño del programa se beneficia de la evolución. Creo que, si uno se fijase, esta sería la forma en que se desarrollaron la mayoría de los programas grandes. Y aquellos que evolucionaron de esta manera probablemente todavía estén escritos en el lenguaje en el que fueron escritos originalmente, porque es raro que un programa sea portado, excepto por razones políticas. Y entonces, paradójicamente, si quieres hacer un lenguaje que se use para sistemas grandes, tienes que hacerlo bueno para escribir programas descartables, porque de ahí provienen los sistemas grandes.
Perl es un ejemplo sorprendente de esta idea. No sólo fue diseñado para escribir programas desechables, sino que era prácticamente un programa desechable en sí mismo. Perl comenzó como una colección de utilidades para generar informes y sólo evolucionó hasta convertirse en un lenguaje de programación a medida que aumentaba el número de programas desechables que la gente escribía en él. No fue hasta Perl 5 (si es que llegó a existir) que el lenguaje fue adecuado para escribir programas serios, y sin embargo ya era enormemente popular.
¿Qué hace que un lenguaje sea bueno para programas desechables? Para empezar, debe estar disponible de inmediato. Un programa desechable es algo que esperas escribir en una hora. Por lo tanto, es probable que el lenguaje ya esté instalado en la computadora que estás usando. No puede ser algo que tengas que instalar antes de usarlo. Tiene que estar ahí. C estaba ahí porque venía con el sistema operativo. Perl estaba ahí porque originalmente era una herramienta para administradores de sistemas, y el tuyo ya lo tenía instalado.
Sin embargo, estar disponible significa más que estar instalado. Un lenguaje interactivo, con una interfaz de línea de comandos, está más disponible que uno que se debe compilar y ejecutar por separado. Un lenguaje de programación popular debe ser interactivo y arrancar rápidamente.
Otra cosa que se busca en un programa desechable es la brevedad. La brevedad siempre resulta atractiva para los hackers, y más aún en un programa que esperan tener listo en una hora.
6 Bibliotecas
Por supuesto, lo último en brevedad es tener el programa ya escrito y simplemente llamarlo. Y esto nos lleva a lo que creo que será una característica cada vez más importante de los lenguajes de programación: las funciones de biblioteca. Perl gana porque tiene grandes bibliotecas para manipular cadenas. Esta clase de funciones de biblioteca son especialmente importantes para los programas desechables, que a menudo se escriben originalmente para convertir o extraer datos. Muchos programas Perl probablemente comienzan como un par de llamadas a bibliotecas unidas.
Creo que muchos de los avances que se produzcan en los lenguajes de programación en los próximos cincuenta años tendrán que ver con las funciones de biblioteca. Creo que los lenguajes de programación del futuro tendrán bibliotecas diseñadas con tanto cuidado como el lenguaje central. El diseño de un lenguaje de programación no se centrará en si se debe hacer que el lenguaje sea fuertemente o débilmente tipado, u orientado a objetos, o funcional, o lo que sea, sino en cómo diseñar grandes bibliotecas. El tipo de diseñadores de lenguajes a los que les gusta pensar en cómo diseñar sistemas de tipos puede estremecerse ante esto. ¡Es casi como escribir aplicaciones! Qué lástima. Los lenguajes son para los programadores, y las bibliotecas son lo que los programadores necesitan.
Es difícil diseñar buenas bibliotecas. No se trata simplemente de escribir mucho código. Cuando las bibliotecas se vuelven demasiado grandes, a veces puede llevar más tiempo encontrar la función que necesitas que escribir el código tú mismo. Las bibliotecas deben diseñarse utilizando un pequeño conjunto de operadores ortogonales, al igual que el lenguaje principal. El programador debe poder adivinar qué llamada a la biblioteca hará lo que necesita.
Las bibliotecas son un aspecto en el que Common Lisp se queda corto. Solo hay bibliotecas rudimentarias para manipular cadenas y casi ninguna para comunicarse con el sistema operativo. Por razones históricas, Common Lisp intenta hacer como si el sistema operativo no existiera. Y como no se puede hablar con el sistema operativo, es poco probable que se pueda escribir un programa serio utilizando solo los operadores integrados en Common Lisp. También hay que utilizar algunos trucos específicos de la implementación y, en la práctica, estos tienden a no ofrecer todo lo que se desea. Los hackers tendrían una opinión mucho mejor de Lisp si Common Lisp tuviera bibliotecas de cadenas potentes y un buen soporte para sistemas operativos.
7 Sintaxis
¿Podría un lenguaje con la sintaxis de Lisp, o más precisamente, con la falta de sintaxis, llegar a ser popular? No sé la respuesta a esta pregunta. Creo que la sintaxis no es la principal razón por la que Lisp no es popular actualmente. El lenguaje Lisp común tiene problemas peores que la sintaxis desconocida. Conozco a varios programadores que se sienten cómodos con la sintaxis de prefijo y, sin embargo, usan Perl por defecto, porque tiene bibliotecas de cadenas potentes y puede comunicarse con el sistema operativo.
Hay dos posibles problemas con la notación de prefijos: que no resulte familiar para los programadores y que no sea lo suficientemente densa. La opinión generalizada en el mundo de Lisp es que el primer problema es el verdadero. No estoy tan seguro. Sí, la notación de prefijos hace que los programadores comunes entren en pánico, pero no creo que las opiniones de los programadores comunes importen. Los lenguajes se vuelven populares o impopulares según lo que los hackers expertos piensen de ellos, y creo que los hackers expertos podrían ser capaces de lidiar con la notación de prefijos. La sintaxis de Perl puede ser bastante incomprensible, pero eso no ha impedido la popularidad de Perl. En todo caso, puede que haya ayudado a fomentar un culto a Perl.
Un problema más grave es la difusión de la notación de prefijos. Para los hackers expertos, eso es un verdadero problema. Nadie quiere escribir (aref axy) cuando podría escribir a[x,y].
En este caso particular, existe una forma de solucionar el problema de forma más sutil. Si tratamos las estructuras de datos como si fueran funciones en índices, podríamos escribir (axy) en su lugar, que es incluso más corta que la forma de Perl. Trucos similares pueden acortar otros tipos de expresiones.
Podemos deshacernos de muchos paréntesis (o hacerlos opcionales) haciendo que la sangría sea significativa. Así es como los programadores leen el código: cuando la sangría dice una cosa y los delimitadores dicen otra, nos guiamos por la sangría. Tratar la sangría como significativa eliminaría esta fuente común de errores y, además, haría que los programas fueran más cortos.
A veces, la sintaxis infija es más fácil de leer. Esto es especialmente cierto para las expresiones matemáticas. He usado Lisp toda mi vida como programador y todavía no encuentro naturales las expresiones matemáticas con prefijo. Y, sin embargo, es conveniente, especialmente cuando se genera código, tener operadores que tomen cualquier número de argumentos. Por lo tanto, si tenemos una sintaxis infija, probablemente debamos implementarla como algún tipo de macro de lectura.
No creo que debamos oponernos religiosamente a la introducción de sintaxis en Lisp, siempre que se traduzca de una manera bien entendida en expresiones s subyacentes. Ya hay una buena cantidad de sintaxis en Lisp. No es necesariamente malo introducir más, siempre que nadie se vea obligado a usarla. En Common Lisp, algunos delimitadores están reservados para el lenguaje, lo que sugiere que al menos algunos de los diseñadores tenían la intención de tener más sintaxis en el futuro.
Una de las partes de sintaxis más escandalosamente antilispy en Common Lisp se encuentra en las cadenas de formato; el formato es un lenguaje por derecho propio, y ese lenguaje no es Lisp. Si hubiera un plan para introducir más sintaxis en Lisp, se podrían incluir especificadores de formato en él. Sería bueno que las macros pudieran generar especificadores de formato de la misma manera que generan cualquier otro tipo de código.
Un eminente hacker de Lisp me dijo que su copia de CLTL se abre al formato de sección. La mía también. Esto probablemente indica que hay margen de mejora. También puede significar que los programas realizan muchas operaciones de E/S.
8 Eficiencia
Como todo el mundo sabe, un buen lenguaje debería generar código rápido. Pero en la práctica no creo que el código rápido provenga principalmente de cosas que se hacen en el diseño del lenguaje. Como señaló Knuth hace mucho tiempo, la velocidad solo importa en ciertos cuellos de botella críticos. Y como muchos programadores han observado desde entonces, uno se equivoca muy a menudo sobre dónde están esos cuellos de botella.
En la práctica, la forma de obtener un código rápido es tener un buen generador de perfiles, en lugar de, por ejemplo, hacer que el lenguaje sea fuertemente tipado. No es necesario conocer el tipo de cada argumento en cada llamada del programa. Es necesario poder declarar los tipos de argumentos en los cuellos de botella. Y, más aún, es necesario poder averiguar dónde están los cuellos de botella.
Una queja que la gente ha tenido con Lisp es que es difícil saber qué es caro. Esto puede ser cierto, pero también puede ser inevitable si se quiere tener un lenguaje muy abstracto. Y en cualquier caso, creo que una buena elaboración de perfiles sería de gran ayuda para solucionar el problema: pronto se sabría qué es caro.
Parte del problema aquí es social. A los diseñadores de lenguajes les gusta escribir compiladores rápidos. Así es como miden sus habilidades. En el mejor de los casos, consideran que el generador de perfiles es un complemento. Pero en la práctica, un buen generador de perfiles puede hacer más por mejorar la velocidad de los programas reales escritos en el lenguaje que un compilador que genera código rápido. En este caso, una vez más, los diseñadores de lenguajes están un poco desconectados de sus usuarios. Hacen un muy buen trabajo al resolver un problema ligeramente equivocado.
Puede ser una buena idea tener un generador de perfiles activo, para enviar datos de rendimiento al programador en lugar de esperar a que venga a pedirlos. Por ejemplo, el editor podría mostrar los cuellos de botella en rojo cuando el programador edite el código fuente. Otro enfoque sería representar de alguna manera lo que está sucediendo en los programas en ejecución. Esto sería una gran ventaja especialmente en aplicaciones basadas en servidor, donde hay muchos programas en ejecución para observar. Un generador de perfiles activo podría mostrar gráficamente lo que está sucediendo en la memoria mientras se ejecuta un programa, o incluso emitir sonidos que indiquen lo que está sucediendo.
El sonido es una buena señal para detectar problemas. En un lugar donde trabajé, teníamos un gran tablero con diales que mostraban lo que estaba sucediendo con nuestros servidores web. Las manecillas se movían mediante pequeños servomotores que hacían un leve ruido al girar. No podía ver el tablero desde mi escritorio, pero descubrí que podía saber de inmediato, por el sonido, cuando había un problema con un servidor.
Incluso podría ser posible escribir un generador de perfiles que detectara automáticamente algoritmos ineficientes. No me sorprendería que ciertos patrones de acceso a la memoria resultaran ser señales seguras de algoritmos defectuosos. Si hubiera un tipo pequeño corriendo por el interior de la computadora ejecutando nuestros programas, probablemente tendría una historia tan larga y lastimera para contar sobre su trabajo como empleado del gobierno federal. A menudo tengo la sensación de que estoy enviando al procesador a muchas búsquedas inútiles, pero nunca he tenido una buena forma de ver lo que está haciendo.
Actualmente, varios lenguajes Lisp compilan en código byte, que luego es ejecutado por un intérprete. Esto se hace generalmente para facilitar la portabilidad de la implementación, pero podría ser una característica útil del lenguaje. Podría ser una buena idea hacer del código byte una parte oficial del lenguaje y permitir a los programadores utilizar código byte en línea en los cuellos de botella. De ese modo, dichas optimizaciones también serían portables.
La naturaleza de la velocidad, tal como la percibe el usuario final, puede estar cambiando. Con el aumento de las aplicaciones basadas en servidores, cada vez más programas pueden resultar limitados por la entrada y salida. Merece la pena hacer que la entrada y salida sean rápidas. El lenguaje puede ayudar con medidas sencillas, como funciones de salida rápidas y formateadas, y también con cambios estructurales profundos, como el almacenamiento en caché y los objetos persistentes.
A los usuarios les interesa el tiempo de respuesta, pero otro tipo de eficiencia será cada vez más importante: la cantidad de usuarios simultáneos que se pueden admitir por procesador. Muchas de las aplicaciones interesantes que se escriban en el futuro cercano estarán basadas en servidores, y la cantidad de usuarios por servidor es la cuestión crítica para cualquiera que aloje dichas aplicaciones. En el costo de capital de una empresa que ofrece una aplicación basada en servidores, este es el divisor.
Durante años, la eficiencia no ha sido de gran importancia en la mayoría de las aplicaciones para el usuario final. Los desarrolladores han podido asumir que cada usuario tendría un procesador cada vez más potente en su escritorio. Y, según la Ley de Parkinson, el software se ha expandido para utilizar los recursos disponibles. Eso cambiará con las aplicaciones basadas en servidores. En ese mundo, el hardware y el software se suministrarán juntos. Para las empresas que ofrecen aplicaciones basadas en servidores, la cantidad de usuarios que pueden admitir por servidor marcará una gran diferencia en el resultado final.
En algunas aplicaciones, el procesador será el factor limitante y la velocidad de ejecución será lo más importante a optimizar. Pero a menudo la memoria será el límite; la cantidad de usuarios simultáneos estará determinada por la cantidad de memoria que necesite para los datos de cada usuario. El lenguaje también puede ayudar en este caso. Un buen soporte para subprocesos permitirá que todos los usuarios compartan un único montón. También puede resultar útil tener objetos persistentes y/o soporte a nivel de lenguaje para carga diferida.
9 Tiempo
El último ingrediente que necesita un lenguaje popular es el tiempo. Nadie quiere escribir programas en un lenguaje que podría desaparecer, como ocurre con tantos lenguajes de programación. Por eso, la mayoría de los hackers tenderán a esperar hasta que un lenguaje haya existido durante un par de años antes de siquiera considerar usarlo.
Los inventores de cosas maravillosas se sorprenden a menudo al descubrir esto, pero se necesita tiempo para que la gente entienda cualquier mensaje. Un amigo mío rara vez hace algo la primera vez que alguien se lo pide. Sabe que a veces la gente pide cosas que resulta que no quiere. Para no perder el tiempo, espera hasta la tercera o cuarta vez que le piden algo; para entonces, quien le esté pidiendo puede estar bastante molesto, pero al menos es probable que realmente quiera lo que está pidiendo.
La mayoría de las personas han aprendido a hacer un tipo de filtrado similar sobre las cosas nuevas que escuchan. Ni siquiera comienzan a prestar atención hasta que han oído hablar de algo diez veces. Y están perfectamente justificados: la mayoría de las novedades que se presentan resultan ser una pérdida de tiempo y, con el tiempo, desaparecen. Al retrasar el aprendizaje de VRML, evité tener que aprenderlo.
Así que cualquiera que invente algo nuevo tiene que esperar repetir su mensaje durante años antes de que la gente empiece a entenderlo. Escribimos lo que fue, hasta donde yo sé, la primera aplicación basada en servidor web, y nos llevó años hacerla llegar a la gente para que no tuviera que descargarla. No es que fueran estúpidos. Simplemente nos hicieron desviar la atención.
La buena noticia es que la simple repetición resuelve el problema. Todo lo que tienes que hacer es seguir contando tu historia y, con el tiempo, la gente empezará a escucharte. No es cuando la gente se da cuenta de que estás ahí que te presta atención, sino cuando se da cuenta de que sigues ahí.
Por suerte, suele llevar un tiempo ganar impulso. La mayoría de las tecnologías evolucionan mucho incluso después de su lanzamiento, especialmente los lenguajes de programación. Nada podría ser mejor, para una nueva tecnología, que unos pocos años de uso por parte de un pequeño número de usuarios pioneros. Los primeros usuarios son sofisticados y exigentes, y rápidamente detectan los fallos que quedan en tu tecnología. Cuando sólo tienes unos pocos usuarios, puedes estar en estrecho contacto con todos ellos. Y los primeros usuarios son indulgentes cuando mejoras tu sistema, incluso si esto causa algún fallo.
Hay dos formas de introducir una nueva tecnología: el método de crecimiento orgánico y el método del big bang. El método de crecimiento orgánico se ejemplifica con la clásica startup improvisada y con poco dinero que surge en un garaje. Un par de personas, trabajando en la oscuridad, desarrollan una nueva tecnología. La lanzan sin marketing y al principio sólo tienen unos pocos usuarios (fanáticamente devotos). Siguen mejorando la tecnología y, mientras tanto, su base de usuarios crece gracias al boca a boca. Antes de que se den cuenta, ya son grandes.
El otro enfoque, el método del big bang, se ejemplifica con la startup respaldada por capital de riesgo y muy promocionada: se apresuran a desarrollar un producto, lo lanzan con gran publicidad e inmediatamente (eso esperan) tienen una gran base de usuarios.
En general, los que trabajan en garajes envidian a los que trabajan en grandes empresas. Los que trabajan en grandes empresas son tranquilos, seguros de sí mismos y respetados por los inversores de capital riesgo. Pueden permitirse lo mejor de todo, y la campaña de relaciones públicas que rodea el lanzamiento tiene el efecto secundario de convertirlos en celebridades. Los que trabajan en crecimiento orgánico, sentados en sus garajes, se sienten pobres y no queridos. Y, sin embargo, creo que a menudo cometen el error de sentir lástima por sí mismos. El crecimiento orgánico parece producir mejor tecnología y fundadores más ricos que el método del big bang. Si observamos las tecnologías dominantes en la actualidad, veremos que la mayoría de ellas crecieron orgánicamente.
Este patrón no sólo se aplica a las empresas. También se puede ver en las investigaciones patrocinadas. Multics y Common Lisp fueron proyectos de gran impacto, y Unix y MacLisp fueron proyectos de crecimiento orgánico.
10 Rediseño
"La mejor manera de escribir es reescribir", escribió EB White. Todo buen escritor lo sabe, y también es cierto en el caso del software. La parte más importante del diseño es el rediseño. Los lenguajes de programación, en particular, no se rediseñan lo suficiente.
Para escribir un buen software es necesario tener en la cabeza dos ideas opuestas al mismo tiempo: la fe ingenua del joven hacker en sus habilidades y, al mismo tiempo, el escepticismo del veterano. Hay que ser capaz de pensar con una mitad del cerebro : "¿Qué tan difícil puede ser?", mientras que con la otra mitad del cerebro se piensa que nunca funcionará .
El truco es darse cuenta de que no hay ninguna contradicción real aquí. Hay que ser optimista y escéptico sobre dos cosas diferentes. Hay que ser optimista sobre la posibilidad de resolver el problema, pero escéptico sobre el valor de cualquier solución que se haya encontrado hasta ahora.
Las personas que hacen un buen trabajo a menudo piensan que lo que están haciendo no es bueno. Los demás ven lo que han hecho y se maravillan, pero el creador está lleno de preocupación. Este patrón no es casualidad: es la preocupación la que hizo que el trabajo fuera bueno.
Si logras mantener un equilibrio entre la esperanza y la preocupación, éstas impulsarán un proyecto de la misma manera que tus dos piernas impulsan una bicicleta. En la primera fase del motor de innovación de dos ciclos, trabajas frenéticamente en algún problema, inspirado por tu confianza en que podrás resolverlo. En la segunda fase, miras lo que has hecho a la fría luz de la mañana y ves todos sus defectos con mucha claridad. Pero mientras tu espíritu crítico no supere a tu esperanza, podrás mirar tu sistema, que reconoces que está incompleto, y pensar: "¿Qué tan difícil puede ser completar el resto del camino?", continuando así el ciclo.
Es complicado mantener el equilibrio entre ambas fuerzas. En los hackers jóvenes predomina el optimismo, producen algo, están convencidos de que es genial y nunca lo mejoran. En los hackers mayores predomina el escepticismo y ni siquiera se atreven a emprender proyectos ambiciosos.
Todo lo que se pueda hacer para que el ciclo de rediseño continúe es bueno. La prosa se puede reescribir una y otra vez hasta que uno esté satisfecho con ella, pero el software, por regla general, no se rediseña lo suficiente. La prosa tiene lectores, pero el software tiene usuarios. Si un escritor reescribe un ensayo, es poco probable que las personas que lean la versión anterior se quejen de que sus ideas se han visto alteradas por alguna incompatibilidad recién introducida.
Los usuarios son un arma de doble filo. Pueden ayudarte a mejorar tu lenguaje, pero también pueden disuadirte de hacerlo. Por lo tanto, elige a tus usuarios con cuidado y aumenta su número lentamente. Tener usuarios es como la optimización: lo más sensato es retrasarla. Además, como regla general, en cualquier momento puedes salirte con la tuya cambiando más de lo que crees. Introducir cambios es como quitarte una venda: el dolor desaparece casi en el mismo momento en que lo sientes.
Todo el mundo sabe que no es buena idea que un comité diseñe un lenguaje. Los comités producen malos diseños. Pero creo que el peor peligro de los comités es que interfieren en el rediseño. Es tanto trabajo introducir cambios que nadie quiere molestarse en hacerlo. Cualquier decisión que tome un comité tiende a permanecer así, incluso si a la mayoría de los miembros no les gusta.
Incluso un comité de dos personas puede ser un obstáculo para el rediseño. Esto sucede especialmente en las interfaces entre piezas de software escritas por dos personas diferentes. Para cambiar la interfaz, ambas personas deben ponerse de acuerdo para cambiarla a la vez. Por eso, las interfaces tienden a no cambiar en absoluto, lo que es un problema porque tienden a ser una de las partes más improvisadas de cualquier sistema.
Una solución podría ser diseñar sistemas de manera que las interfaces sean horizontales en lugar de verticales, de modo que los módulos sean siempre estratos de abstracción apilados verticalmente. En ese caso, la interfaz tenderá a ser propiedad de uno de ellos. El nivel inferior de los dos será un lenguaje en el que está escrito el superior, en cuyo caso el nivel inferior será el propietario de la interfaz, o será un esclavo, en cuyo caso la interfaz puede ser dictada por el nivel superior.
11 Ceceo
Todo esto implica que hay esperanza para un nuevo Lisp. Hay esperanza para cualquier lenguaje que dé a los hackers lo que quieren, incluido Lisp. Creo que tal vez hayamos cometido un error al pensar que a los hackers les desagrada la rareza de Lisp. Esta ilusión reconfortante puede habernos impedido ver el verdadero problema de Lisp, o al menos de Common Lisp, que es que es una porquería para hacer lo que los hackers quieren hacer. El lenguaje de un hacker necesita bibliotecas potentes y algo que hackear. Common Lisp no tiene ninguna de las dos cosas. El lenguaje de un hacker es conciso y hackeable. Common Lisp no lo es.
La buena noticia es que no es Lisp lo que apesta, sino Common Lisp. Si podemos desarrollar un nuevo Lisp que sea un lenguaje de hackers de verdad, creo que los hackers lo usarán. Usarán cualquier lenguaje que haga el trabajo. Todo lo que tenemos que hacer es asegurarnos de que este nuevo Lisp haga alguna tarea importante mejor que otros lenguajes.
La historia nos da algunos ánimos. Con el tiempo, los nuevos lenguajes de programación han ido incorporando cada vez más características de Lisp. Ya no queda mucho por copiar antes de que el lenguaje que hemos creado sea Lisp. El último lenguaje de moda, Python, es una versión diluida de Lisp con sintaxis infija y sin macros. Un nuevo Lisp sería un paso natural en esta progresión.
A veces pienso que sería un buen truco de marketing llamarlo una versión mejorada de Python. Eso suena más moderno que Lisp. Para mucha gente, Lisp es un lenguaje de IA lento con muchos paréntesis. La biografía oficial de Fritz Kunze evita cuidadosamente mencionar la palabra que empieza por L. Pero supongo que no deberíamos tener miedo de llamar Lisp al nuevo Lisp. Lisp todavía tiene mucho respeto latente entre los mejores hackers (los que tomaron la versión 6.001 y la entendieron, por ejemplo). Y esos son los usuarios que necesitas ganar.
En "Cómo convertirse en hacker", Eric Raymond describe Lisp como algo así como el latín o el griego: un idioma que debes aprender como ejercicio intelectual, aunque en realidad no lo uses:
Vale la pena aprender Lisp por la profunda experiencia de iluminación que tendrás cuando finalmente lo comprendas; esa experiencia te convertirá en un mejor programador para el resto de tus días, incluso si en realidad nunca usas mucho Lisp.
Si no conociera Lisp, leer esto me haría plantearme algunas preguntas. Un lenguaje que me haría un mejor programador, si es que eso significa algo, significa un lenguaje que sería mejor para programar. Y eso es, de hecho, lo que implica lo que dice Eric.
Mientras esa idea siga circulando, creo que los hackers serán lo suficientemente receptivos a un nuevo Lisp, incluso si se llama Lisp. Pero este Lisp debe ser un lenguaje de hackers, como los Lisp clásicos de los años 70. Debe ser conciso, simple y hackeable. Y debe tener bibliotecas potentes para hacer lo que los hackers quieren hacer ahora.
En materia de bibliotecas, creo que hay margen para superar a lenguajes como Perl y Python en su propio terreno. Muchas de las nuevas aplicaciones que se necesitarán escribir en los próximos años serán aplicaciones basadas en servidor . No hay ninguna razón por la que un nuevo Lisp no deba tener bibliotecas de cadenas tan buenas como Perl, y si este nuevo Lisp también tuviera bibliotecas potentes para aplicaciones basadas en servidor, podría ser muy popular. Los verdaderos hackers no se burlarán de una nueva herramienta que les permita resolver problemas difíciles con unas pocas llamadas a bibliotecas. Recuerden, los hackers son vagos.
Podría ser un logro aún mayor contar con un soporte de lenguaje básico para aplicaciones basadas en servidor. Por ejemplo, soporte explícito para programas con múltiples usuarios o propiedad de datos a nivel de etiquetas de tipo.
Las aplicaciones basadas en servidor también nos dan la respuesta a la pregunta de qué se usará este nuevo Lisp para hackear. No estaría mal mejorar Lisp como lenguaje de scripting para Unix (sería difícil empeorarlo), pero creo que hay áreas en las que sería más fácil superar a los lenguajes existentes. Creo que podría ser mejor seguir el modelo de Tcl y proporcionar a Lisp junto con un sistema completo para soportar aplicaciones basadas en servidor. Lisp es un ajuste natural para aplicaciones basadas en servidor. Los cierres léxicos proporcionan una manera de obtener el efecto de las subrutinas cuando la interfaz de usuario es simplemente una serie de páginas web. Las expresiones S se asignan bien al HTML y las macros son buenas para generarlas. Es necesario que haya mejores herramientas para escribir aplicaciones basadas en servidor y que haya un nuevo Lisp, y los dos funcionarían muy bien juntos.
12 El lenguaje de los sueños
A modo de resumen, intentemos describir el lenguaje soñado del hacker. El lenguaje soñado es hermoso , limpio y conciso. Tiene un nivel superior interactivo que se inicia rápidamente. Puedes escribir programas para resolver problemas comunes con muy poco código. Casi todo el código de cualquier programa que escribas es código específico para tu aplicación. Todo lo demás ya lo hemos hecho por ti.
La sintaxis del lenguaje es demasiado breve, por lo que nunca es necesario escribir un carácter innecesario ni utilizar demasiado la tecla Shift.
Si utilizas grandes abstracciones, puedes escribir la primera versión de un programa muy rápidamente. Más adelante, cuando quieras optimizarlo, existe un generador de perfiles muy bueno que te indica dónde centrar tu atención. Puedes crear bucles internos a una velocidad increíble, incluso escribiendo código de bytes en línea si es necesario.
Hay muchos buenos ejemplos de los que aprender y el lenguaje es lo suficientemente intuitivo como para que puedas aprender a usarlo a partir de ejemplos en un par de minutos. No necesitas consultar mucho el manual. El manual es breve y tiene pocas advertencias y salvedades.
El lenguaje tiene un núcleo pequeño y bibliotecas potentes y altamente ortogonales que están diseñadas con tanto cuidado como el lenguaje principal. Todas las bibliotecas funcionan bien juntas; todo en el lenguaje encaja como las partes de una buena cámara. No se descarta nada ni se conserva nada por razones de compatibilidad. El código fuente de todas las bibliotecas está disponible. Es fácil comunicarse con el sistema operativo y con aplicaciones escritas en otros lenguajes.
El lenguaje está construido en capas. Las abstracciones de nivel superior se construyen de forma muy transparente a partir de abstracciones de nivel inferior, a las que puedes acceder si lo deseas.
No se te oculta nada que no sea absolutamente necesario. El lenguaje ofrece abstracciones sólo como una forma de ahorrarte trabajo, en lugar de como una forma de decirte qué hacer. De hecho, el lenguaje te anima a participar en su diseño en igualdad de condiciones. Puedes cambiar todo lo que contiene, incluida la sintaxis, y todo lo que escribas tiene, en la medida de lo posible, el mismo estatus que lo que viene predefinido.
Notas
[1] En 1964, dos años después de que se lanzara Lisp 1.5, Timothy Hart propuso macros muy similares a la idea moderna. Lo que faltaba, inicialmente, eran formas de evitar la captura de variables y la evaluación múltiple; los ejemplos de Hart están sujetos a ambas.
[2] En Cuando el aire golpea tu cerebro, el neurocirujano Frank Vertosick relata una conversación en la que su jefe de residentes, Gary, habla sobre la diferencia entre cirujanos e internistas ("pulgas"):
Gary y yo pedimos una pizza grande y encontramos un reservado libre. El jefe encendió un cigarrillo. "Mira esas malditas pulgas, parloteando sobre alguna enfermedad que verán una vez en sus vidas. Ese es el problema con las pulgas, solo les gustan las cosas raras. Odian sus bocadillos de pan y mantequilla. Esa es la diferencia entre nosotros y las malditas pulgas. Verás, a nosotros nos encantan las hernias discales lumbares grandes y jugosas, pero ellas odian la hipertensión..."
Es difícil pensar en una hernia de disco lumbar como algo jugoso (excepto en sentido literal). Y, sin embargo, creo que sé lo que significan. A menudo he tenido que rastrear un error jugoso. A alguien que no sea programador le resultaría difícil imaginar que un error pueda ser placentero. Sin duda, es mejor que todo funcione. En cierto modo, lo es. Y, sin embargo, es innegable que existe una satisfacción sombría en la búsqueda de ciertos tipos de errores.