Loading...

SER POPULAR

Original

Mayo de 2001

(Este artículo fue escrito como una especie de plan de negocios para un nuevo lenguaje. Así que le falta (porque lo da por sentado) la característica más importante de un buen lenguaje de programación: abstracciones muy poderosas.)

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 dijo que sería una pérdida de tiempo, que los lenguajes de programación no se vuelven populares o impopulares en base a sus méritos, y que por lo tanto no importaba lo bueno que fuera su lenguaje, nadie lo usaría. Al menos, eso era lo que le había pasado al lenguaje que él había diseñado.

¿Qué hace que un lenguaje sea popular? ¿Los lenguajes populares se 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 mirando a los hackers y aprendiendo lo que quieren. Los lenguajes de programación son para hackers, y un lenguaje de programación es bueno como lenguaje de programación (en lugar de, digamos, 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 simplemente en base a sus méritos. La mayoría de los programadores les dicen qué lenguaje usar a alguien más. Y sin embargo, creo que el efecto de tales 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 de 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 diseñarse para adaptarse a las fortalezas y debilidades humanas tanto como los zapatos deben diseñarse para los pies humanos. Si un zapato aprieta al ponértelo, es un mal zapato, por muy elegante que sea como obra de escultura.

Puede que la mayoría de los programadores no puedan distinguir un buen lenguaje de uno malo. Pero eso no es diferente con ninguna otra herramienta. No significa que sea una pérdida de tiempo intentar diseñar un buen lenguaje. Hackers expertos pueden saber un buen lenguaje cuando lo ven, y lo usarán. Los hackers expertos son una pequeña minoría, es cierto, pero esa pequeña minoría escribe todo el buen software, y su influencia es tal que el resto de los programadores tenderán a usar cualquier lenguaje que usen ellos. A menudo, de hecho, no es meramente influencia, sino mando: a menudo los hackers expertos son precisamente las personas que, como sus jefes o asesores de 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 exageración (Ada, Java) también juegan un papel — pero creo que es la fuerza más poderosa a largo plazo. Dada una masa crítica inicial y tiempo suficiente, un lenguaje de programación probablemente se vuelve tan popular como se merece. Y la popularidad separa aún más los buenos lenguajes de los malos, porque la retroalimentación de usuarios reales siempre conduce a mejoras. Mira cuánto ha cambiado cualquier lenguaje popular durante su vida. Perl y Fortran son casos extremos, pero incluso Lisp ha cambiado mucho. Lisp 1.5 no tenía macros, por ejemplo; estas evolucionaron más tarde, después de que los hackers del MIT hubieran pasado un par de años usando Lisp para escribir programas reales. [1]

Así que, independientemente de si un lenguaje tiene que ser bueno 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 queda quieto. Y sin embargo, los Lisps que tenemos hoy en día siguen siendo casi los mismos que tenían en el MIT a mediados de la década de 1980, porque esa fue la última vez que Lisp tuvo una base de usuarios lo suficientemente grande y exigente.

Por supuesto, los hackers tienen que saber sobre un lenguaje antes de poder usarlo. ¿Cómo van a enterarse? De otros hackers. Pero tiene que haber algún grupo inicial de hackers usando el lenguaje para que otros incluso se enteren de él. Me pregunto qué tan grande tiene que ser este grupo; ¿cuántos usuarios hacen una masa crítica? A bote pronto, diría veinte. Si un lenguaje tuviera veinte usuarios separados, es decir, veinte usuarios que decidieran por su cuenta usarlo, lo consideraría real.

Llegar allí no puede ser fácil. No me sorprendería si es más difícil llegar de cero a veinte que de veinte a mil. La mejor manera de conseguir esos veinte usuarios iniciales es probablemente usar un caballo de Troya: dar a la gente una aplicación que quieren, la cual resulta estar escrita en el nuevo lenguaje.

2 Factores externos

Empecemos por reconocer un factor externo que sí afecta a la popularidad de un lenguaje de programación. Para volverse popular, un lenguaje de programación tiene que ser el lenguaje de scripting de un sistema popular. Fortran y Cobol fueron los lenguajes de scripting de los primeros mainframes de IBM. C fue el lenguaje de scripting de Unix, y por lo tanto, más tarde, lo fue Perl. Tcl es el lenguaje de scripting de Tk. Java y Javascript están destinados a ser los lenguajes de scripting de los navegadores web.

Lisp no es un lenguaje masivamente popular porque no es el lenguaje de scripting de un sistema masivamente popular. La popularidad que conserva se remonta a la década de 1960 y 1970, cuando era el lenguaje de scripting del MIT. Muchos de los grandes programadores de la época estuvieron asociados con el MIT en algún momento. Y a principios de la década de 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 scripting de dos sistemas moderadamente populares, Emacs y Autocad, y por esa razón sospecho que la mayoría 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. Para hackear es un verbo transitivo — los hackers suelen hackear algo — y en la práctica, los lenguajes se juzgan en relación con lo que se usan para hackear. Así que 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 un huérfano. En un principio venía con un sistema para hackear: la Lisp Machine. Pero las Lisp Machines (junto con las computadoras paralelas) fueron aplastadas por el aumento de la 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 scripting para Unix. Es, por desgracia, un pésimo.

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 en realidad no es un lenguaje de programación a menos que también sea el lenguaje de scripting de algo. Esto sólo parece injusto si te sorprende. Creo que no es más injusto que esperar que un lenguaje de programación tenga, digamos, una implementación. Es solo parte de lo que es un lenguaje de programación.

Un lenguaje de programación sí necesita una buena implementación, por supuesto, y esta debe ser gratuita. Las empresas pagarán por el software, pero los individuos hackers no, y son los hackers a los que necesitas atraer.

Un lenguaje también necesita tener un libro sobre él. El libro debe ser delgado, bien escrito y lleno de buenos ejemplos. K&R es el ideal aquí. En este momento, diría que un lenguaje tiene que tener un libro publicado por O'Reilly. Esa se está convirtiendo en la prueba de que importa a los hackers.

También debe 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 estén desfasados todavía. Su formato es práctico, y la de facto censura 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 lenguajes.

3 Brevedad

Dado que puedes proporcionar las tres cosas que necesita cualquier lenguaje — una implementación gratuita, un libro y algo que hackear — ¿cómo haces un lenguaje que a los hackers les guste?

Una cosa que les gusta a los hackers es la brevedad. Los hackers son perezosos, en el mismo sentido en que los matemáticos y los arquitectos modernistas son perezosos: odian cualquier cosa que sea superflua. No estaría muy lejos de la verdad decir que un hacker que está a punto de escribir un programa decide qué lenguaje usar, al menos inconscientemente, en base al número total de caracteres que tendrá que escribir. Si esto no es precisamente cómo piensan los hackers, un diseñador de lenguaje haría bien en actuar como si lo fuera.

Es un error intentar mimar al usuario con expresiones largas que están destinadas a parecerse al inglés. Cobol es notorio por esta falla. Un hacker consideraría que le pidieran escribir

add x to y giving 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. Tal vez durante las primeras dos horas. Pero un hacker puede aprender lo suficientemente rápido que car significa el primer elemento de una lista y cdr significa el resto. Usar first y rest significa un 50% más de escritura. Y también son de diferente longitud, lo que significa que los argumentos no se alinearán cuando se llamen, como a menudo lo hacen car y cdr, en líneas sucesivas. He encontrado que importa mucho cómo se alinea el código en la página. Apenas puedo leer código Lisp cuando se establece en una fuente de ancho variable, y mis amigos dicen que esto es cierto para otros lenguajes también.

La brevedad es un lugar donde pierden los lenguajes fuertemente tipados. Todas las demás cosas siendo iguales, nadie quiere empezar un programa con un montón de declaraciones. Cualquier cosa que pueda ser implícita, debería serlo.

Los tokens individuales también deben ser cortos. Perl y Common Lisp ocupan polos opuestos en esta cuestión. Los programas Perl pueden ser casi cripticamente 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 largos nombres 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 Capacidad de manipulación

Hay una cosa más importante que la brevedad para un hacker: ser capaz de hacer lo que quieras. En la historia de los lenguajes de programación se ha dedicado un esfuerzo sorprendente a evitar que los programadores hagan cosas consideradas como impropias. Este es un plan peligrosamente presuntuoso. ¿Cómo puede el diseñador del lenguaje saber qué va a necesitar hacer el programador? Creo que los diseñadores de lenguajes harían mejor en considerar que su usuario objetivo es un genio que necesitará 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. Puedes salvarlo de referirse a variables en otro paquete, pero no puedes salvarlo de escribir un programa mal diseñado para resolver el problema equivocado, y tardar una eternidad en hacerlo.

Los buenos programadores a menudo quieren hacer cosas peligrosas y desagradables. Por desagradables me refiero a cosas que van por detrás de cualquier fachada semántica que el lenguaje esté intentando presentar: obtener la representación interna de alguna abstracción de alto nivel, por ejemplo. A los hackers les gusta hackear, y hackear significa entrar en las cosas y cuestionar al diseñador original.

Déjate cuestionar. Cuando haces una herramienta, la gente la usa de formas que no tenías intención, y esto es especialmente cierto en el caso de una herramienta altamente articulada como un lenguaje de programación. Muchos hackers querrán ajustar tu modelo semántico de una manera que tú nunca imaginaste. Te digo, déjalos; dale al programador acceso a la mayor cantidad de cosas internas como puedas sin poner en peligro los sistemas en tiempo de ejecución como el recolector de basura.

En Common Lisp a menudo he querido iterar a través de los campos de una estructura — para eliminar las referencias a un objeto eliminado, por ejemplo, o encontrar campos que no estén inicializados. Sé que las estructuras son solo vectores por debajo. Y sin embargo, no puedo escribir una función de propósito general que pueda llamar a cualquier estructura. Solo puedo acceder a los campos por nombre, porque eso es lo que se supone que significa una estructura.

Un hacker puede que sólo quiera subvertir el modelo previsto de las cosas una vez o dos veces en un programa grande. Pero qué diferencia hace poder hacerlo. Y puede ser más que una cuestión de simplemente resolver un problema. También hay un tipo de placer aquí. Los hackers comparten el placer secreto del cirujano de hurgar en las entrañas, el placer secreto del adolescente de reventar granos. [2] Para los niños, al menos, ciertas clases de horrores son fascinantes. La revista Maxim publica un volumen anual de fotografías, que contiene una mezcla de pin-ups y accidentes espeluznantes. Conocen a su público.

Históricamente, Lisp ha sido bueno para dejar que los hackers hagan lo que quieran. La corrección política de Common Lisp es una aberración. Los Lisps tempranos te dejaban meter las manos en todo. Una buena parte de ese espíritu se conserva, afortunadamente, en las macros. ¡Qué cosa tan maravillosa, poder hacer transformaciones arbitrarias en el código fuente!

Las macros clásicas son una herramienta real para hackers — simples, poderosas y peligrosas. Es tan fácil entender lo que hacen: se llama a una función en los argumentos de la macro, y lo que devuelve se inserta en lugar de la llamada a la macro. Las macros higiénicas encarnan el principio opuesto. Intentan protegerte de entender lo que están haciendo. Nunca he oído explicar las macros higiénicas en una sola frase. Y son un ejemplo clásico de los peligros de decidir qué es lo que los programadores están permitidos a querer. Las macros higiénicas están destinadas a 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 debería ser limpio y sucio a la vez: limpiamente diseñado, con un pequeño núcleo de operadores bien entendidos y altamente ortogonales, pero sucio en el sentido de que permite a los hackers hacer lo que quieran con él. C es así. También lo fueron los primeros Lisps. El lenguaje de un verdadero hacker siempre tendrá un carácter ligeramente pícaro.

Un buen lenguaje de programación debe tener características que hagan que el tipo de personas que usan la frase "ingeniería de software" sacudan la cabeza desaprobatoriamente. En el otro extremo del continuo están lenguajes como Ada y Pascal, modelos de propiedad que son buenos para la enseñanza y no mucho más.

5 Programas desechables

Para ser atractivo para los hackers, un lenguaje debe ser bueno para escribir los tipos de programas que quieren escribir. Y eso significa, tal vez sorprendentemente, que tiene que ser bueno 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 reales y usuarios reales.

Tengo la corazonada de que los mejores programas grandes comienzan su vida de esta manera, en lugar de ser diseñados como grandes desde el principio, como la presa Hoover. Es aterrador construir algo grande desde cero. Cuando la gente se embarca en un proyecto que es demasiado grande, se sienten abrumados. El proyecto se atasca, o el resultado es estéril y de madera: un centro comercial en lugar de un verdadero centro, Brasilia en lugar de Roma, Ada en lugar de C.

Otra forma de obtener un programa grande es empezar con un programa desechable 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 mirara, esto resultaría ser la forma en que se desarrollaron la mayoría de los programas grandes. Y los que sí evolucionaron de esta manera probablemente están todavía escritos en el lenguaje en el que se escribieron por primera vez, porque es raro que un programa se porte, excepto por razones políticas. Y así, paradójicamente, si quieres hacer un lenguaje que se use para sistemas grandes, tienes que hacerlo bueno para escribir programas desechables, porque de ahí es de donde vienen los sistemas grandes.

Perl es un ejemplo llamativo de esta idea. No sólo fue diseñado para escribir programas desechables, sino que era casi un programa desechable en sí mismo. Perl comenzó su vida como una colección de utilidades para generar informes, y solo evolucionó hasta convertirse en un lenguaje de programación a medida que los programas desechables que la gente escribía en él se hacían más grandes. No fue hasta Perl 5 (si es que fue así) que el lenguaje fue adecuado para escribir programas serios, y sin embargo, ya era masivamente popular.

¿Qué hace que un lenguaje sea bueno para los programas desechables? Para empezar, debe estar fácilmente disponible. Un programa desechable es algo que esperas escribir en una hora. Así que el lenguaje probablemente debe estar ya instalado en el ordenador que estás usando. No puede ser algo que tengas que instalar antes de usarlo. Tiene que estar ahí. C estaba allí porque venía con el sistema operativo. Perl estaba allí porque era originalmente una herramienta para administradores de sistemas, y el tuyo ya la había instalado.

Estar disponible significa más que estar instalado, sin embargo. Un lenguaje interactivo, con una interfaz de línea de comandos, está más disponible que uno que tengas que compilar y ejecutar por separado. Un lenguaje de programación popular debería ser interactivo, y arrancar rápidamente.

Otra cosa que quieres en un programa desechable es la brevedad. La brevedad siempre es atractiva para los hackers, y nunca más que en un programa que esperan que salga en una hora.

6 Bibliotecas

Por supuesto, la máxima brevedad es tener el programa ya escrito para ti, 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: funciones de biblioteca. Perl gana porque tiene grandes bibliotecas para manipular cadenas de texto. 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 empiezan como solo un par de llamadas a la biblioteca pegadas juntas.

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 que estén tan cuidadosamente diseñadas como el lenguaje central. El diseño de los lenguajes de programación no será acerca de si hacer que tu lenguaje sea fuertemente o débilmente tipado, u orientado a objetos, o funcional, o lo que sea, sino acerca de 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 con esto. ¡Es casi como escribir aplicaciones! Lástima. Los lenguajes son para programadores, y las bibliotecas son lo que necesitan los programadores.

Es difícil diseñar buenas bibliotecas. No es simplemente una cuestión de escribir mucho código. Una vez que las bibliotecas se vuelven demasiado grandes, puede que a veces lleve 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 central. Debería ser posible que el programador adivine qué llamada a la biblioteca hará lo que necesita.

Las bibliotecas son un lugar donde Common Lisp se queda corto. Solo hay bibliotecas rudimentarias para manipular cadenas de texto, y casi ninguna para hablar con el sistema operativo. Por razones históricas, Common Lisp intenta pretender que el SO no existe. Y como no puedes hablar con el SO, es poco probable que puedas escribir un programa serio usando solo los operadores integrados de Common Lisp. Tienes que usar algunas piraterías específicas de la implementación, y en la práctica estas tienden a no darte todo lo que quieres. Los hackers pensarían mucho más en Lisp si Common Lisp tuviera potentes bibliotecas de cadenas de texto y un buen soporte para el SO.

7 Sintaxis

¿Podría un lenguaje con la sintaxis de Lisp, o más precisamente, la falta de sintaxis, alguna vez volverse popular? No conozco la respuesta a esta pregunta. Sí creo que la sintaxis no es la principal razón por la que Lisp no es actualmente popular. Common Lisp tiene peores problemas 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 potentes bibliotecas de cadenas de texto y puede hablar con el sistema operativo.

Hay dos posibles problemas con la notación de prefijo: que es desconocida para los programadores, y que no es lo suficientemente densa. La sabiduría convencional en el mundo de Lisp es que el primer problema es el real. No estoy tan seguro. Sí, la notación de prefijo hace que los programadores ordinarios entren en pánico. Pero no creo que las opiniones de los programadores ordinarios importen. Los lenguajes se vuelven populares o impopulares en base a lo que piensan los hackers expertos, y creo que los hackers expertos podrían ser capaces de lidiar con la notación de prefijo. La sintaxis de Perl puede ser bastante incomprensible, pero eso no se ha interpuesto en el camino de la popularidad de Perl. Si acaso puede haber ayudado a fomentar un culto a Perl.

Un problema más grave es la difusidad de la notación de prefijo. Para los hackers expertos, ese es realmente un problema. Nadie quiere escribir (aref a x y) cuando podría escribir a[x,y].

En este caso particular hay una forma de salir del problema. Si tratamos las estructuras de datos como si fueran funciones en índices, podríamos escribir (a x y) en su lugar, que es incluso más corto que la forma de Perl. Trucos similares pueden acortar otros tipos de expresiones.

Podemos eliminar (o hacer opcional) muchos paréntesis haciendo que la sangría sea significativa. Así es como los programadores leen el código de todos modos: cuando la sangría dice una cosa y los delimitadores dicen otra, nosotros vamos por la sangría. Tratar la sangría como significativa eliminaría esta fuente común de errores, además de hacer que los programas sean 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 de programador y todavía no me parecen naturales las expresiones matemáticas de prefijo. Y sin embargo, es conveniente, especialmente cuando se genera código, tener operadores que tomen cualquier número de argumentos. Así que si tenemos sintaxis infija, probablemente debería implementarse como una especie de macro de lectura.

No creo que debamos oponernos religiosamente a introducir sintaxis en Lisp, siempre y cuando se traduzca de una manera bien entendida en s-expresiones subyacentes. Ya hay una buena cantidad de sintaxis en Lisp. No es necesariamente malo introducir más, siempre y cuando nadie se vea obligado a usarlo. 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.

Uno de los fragmentos de sintaxis más egregiamente no lisp en Common Lisp se produce en las cadenas de formato; format es un lenguaje en sí mismo, y ese lenguaje no es Lisp. Si hubiera un plan para introducir más sintaxis en Lisp, los especificadores de formato podrían incluirse en ella. 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 en la sección format. La mía también. Esto probablemente indica que hay margen de mejora. También puede significar que los programas hacen mucho de E/S.

8 Eficiencia

Un buen lenguaje, como todo el mundo sabe, debería generar código rápido. Pero en la práctica, no creo que el código rápido provenga principalmente de las 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 suele estar muy equivocado sobre dónde están estos cuellos de botella.

Así que, en la práctica, la forma de obtener código rápido es tener un muy buen perfilador, en lugar de, digamos, hacer que el lenguaje sea fuertemente tipado. No necesitas conocer el tipo de cada argumento en cada llamada en el programa. Sí necesitas ser capaz de declarar los tipos de argumentos en los cuellos de botella. Y aún más, necesitas ser capaz de 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 podría ser cierto. También podría ser inevitable, si quieres tener un lenguaje muy abstracto. Y en cualquier caso, creo que un buen perfilador serviría de mucho para solucionar el problema: enseguida aprenderías 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 su habilidad. Piensan en el perfilador como un añadido, en el mejor de los casos. Pero en la práctica, un buen perfilador puede hacer más para mejorar la velocidad de los programas reales escritos en el lenguaje que un compilador que genera código rápido. Aquí, de nuevo, los diseñadores de lenguajes están algo fuera de contacto con sus usuarios. Hacen un muy buen trabajo resolviendo un problema ligeramente equivocado.

Podría ser una buena idea tener un perfilador activo — para enviar los datos de rendimiento al programador en lugar de esperar a que él vaya a pedírselos. Por ejemplo, el editor podría mostrar los cuellos de botella en rojo cuando el programador edita 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 victoria, especialmente en las aplicaciones basadas en servidores, donde tienes muchos programas en ejecución que observar. Un perfilador activo podría mostrar gráficamente lo que está sucediendo en la memoria mientras se ejecuta un programa, o incluso hacer sonidos que indiquen lo que está sucediendo.

El sonido es una buena pista para los problemas. En un lugar donde trabajé, teníamos un gran tablero de diales que mostraban lo que estaba sucediendo en nuestros servidores web. Las manecillas eran movidas por pequeños servomotores que hacían un ligero ruido cuando giraban. No podía ver el tablero desde mi escritorio, pero me di cuenta de que podía saber inmediatamente, por el sonido, cuando había un problema con un servidor.

Incluso podría ser posible escribir un perfilador que detectara automáticamente algoritmos ineficientes. No me sorprendería si ciertos patrones de acceso a la memoria resultaran ser señales seguras de algoritmos malos. Si hubiera un pequeño hombre corriendo dentro de la computadora ejecutando nuestros programas, probablemente tendría una historia tan larga y lamentosa que contar sobre su trabajo como empleado del gobierno federal. A menudo tengo la sensación de que estoy enviando al procesador a muchas cacerías de gansos salvajes, pero nunca he tenido una buena manera de mirar lo que está haciendo.

Varios Lisps ahora compilan en bytecode, que luego es ejecutado por un intérprete. Esto suele hacerse para facilitar la implementación de la portabilidad, pero podría ser una característica útil del lenguaje. Podría ser una buena idea hacer que el bytecode sea una parte oficial del lenguaje, y permitir a los programadores usar bytecode en línea en los cuellos de botella. Entonces, esas optimizaciones también serían portables.

La naturaleza de la velocidad, tal como la percibe el usuario final, puede estar cambiando. Con el auge de las aplicaciones basadas en servidores, cada vez más programas pueden resultar ser de enlace a E/S. Valdrá la pena hacer que la E/S sea rápida. El lenguaje puede ayudar con medidas sencillas como funciones de salida simples, rápidas y formateadas, y también con cambios estructurales profundos como el almacenamiento en caché y los objetos persistentes.

Los usuarios están interesados en el tiempo de respuesta. Pero otro tipo de eficiencia será cada vez más importante: el número de usuarios simultáneos que puedes soportar por procesador. Muchas de las aplicaciones interesantes que se escriban en el futuro estarán basadas en servidores, y el número de usuarios por servidor es la pregunta crítica para cualquiera que aloje esas aplicaciones. En el costo de capital de un negocio que ofrece una aplicación basada en servidor, este es el divisor.

Durante años, la eficiencia no ha importado mucho en la mayoría de las aplicaciones de usuario final. Los desarrolladores han podido asumir que cada usuario tendría un procesador cada vez más potente en su escritorio. Y por la Ley de Parkinson, el software se ha expandido para usar 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, hará una gran diferencia en el resultado final cuántos usuarios pueden soportar por servidor.

En algunas aplicaciones, el procesador será el factor limitante, y la velocidad de ejecución será lo más importante que optimizar. Pero a menudo la memoria será el límite; el número de usuarios simultáneos estará determinado por la cantidad de memoria que necesitas para cada dato del usuario. El lenguaje también puede ayudar aquí. Un buen soporte para los hilos permitirá a todos los usuarios compartir un único montón. También puede ser útil tener objetos persistentes y/o soporte de nivel de lenguaje para la carga diferida.

9 Tiempo

El último ingrediente que necesita un lenguaje popular es el tiempo. Nadie quiere escribir programas en un lenguaje que pueda desaparecer, como tantos lenguajes de programación lo hacen. Así que 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 nuevas y maravillosas a menudo se sorprenden al descubrir esto, pero se necesita tiempo para hacer llegar cualquier mensaje a la gente. Un amigo mío rara vez hace algo la primera vez que alguien se lo pide. Él sabe que la gente a veces pide cosas que luego resulta que no quiere. Para evitar perder su tiempo, espera hasta la tercera o cuarta vez que le piden que haga algo; para entonces, quienquiera que le esté pidiendo algo puede que esté bastante molesto, pero al menos probablemente realmente quieran lo que están pidiendo.

La mayoría de la gente ha aprendido a hacer un tipo similar de filtrado de las cosas nuevas que escucha. Ni siquiera empiezan a prestar atención hasta que han oído hablar de algo diez veces. Están perfectamente justificados: la mayoría de los hot new whatevers resultan ser una pérdida de tiempo, y eventualmente desaparecen. Al retrasar el aprendizaje de VRML, evité tener que aprenderlo del todo.

Así que cualquiera que invente algo nuevo tiene que esperar a seguir repitiendo su mensaje durante años antes de que la gente empiece a entenderlo. Nosotros escribimos lo que fue, hasta donde yo sé, la primera aplicación basada en servidor web, y nos llevó años hacerles entender a la gente que no tenía que descargarse. No era que fueran estúpidos. Simplemente nos habían silenciado.

La buena noticia es que la simple repetición resuelve el problema. Todo lo que tienes que hacer es seguir contando tu historia, y eventualmente la gente empezará a escuchar. No es cuando la gente se da cuenta de que estás ahí cuando te prestan atención; es cuando se dan cuenta de que todavía estás ahí.

Es bueno que normalmente lleve un tiempo ganar impulso. La mayoría de las tecnologías evolucionan mucho incluso después de que se lanzan por primera vez — los lenguajes de programación especialmente. Nada podría ser mejor, para una nueva tecnología, que unos pocos años de ser utilizada solo por un pequeño número de primeros adoptantes. Los primeros adoptantes son sofisticados y exigentes, y rápidamente sacan a la luz cualquier fallo que quede en tu tecnología. Cuando solo tienes unos pocos usuarios, puedes estar en contacto cercano con todos ellos. Y los primeros adoptantes son indulgentes cuando mejoras tu sistema, incluso si esto provoca alguna ruptura.

Hay dos formas en que se introduce la nueva tecnología: el método de crecimiento orgánico, y el método del big bang. El método de crecimiento orgánico está ejemplificado por la clásica empresa de garaje con poco presupuesto y dirigida por la intuición. Un par de tipos, trabajando en la oscuridad, desarrollan alguna nueva tecnología. La lanzan sin marketing y al principio solo tienen unos pocos (fanáticamente devotos) usuarios. Continúan mejorando la tecnología, y mientras tanto, su base de usuarios crece por el boca a boca. Antes de que se den cuenta, son grandes.

El otro enfoque, el método del big bang, está ejemplificado por la empresa con respaldo de capital riesgo y fuertemente comercializada. Se apresuran a desarrollar un producto, lo lanzan con una gran publicidad, y de inmediato (esperan) tienen una gran base de usuarios.

Generalmente, los tipos de garaje envidian a los tipos del big bang. Los tipos del big bang son suaves y confiados y respetados por los VC. Pueden permitirse lo mejor de todo, y la campaña de relaciones públicas que rodea el lanzamiento tiene el efecto secundario de hacerlos celebridades. Los tipos del crecimiento orgánico, sentados en su garaje, se sienten pobres y sin amor. Y sin embargo, creo que a menudo se equivocan al sentirse mal por sí mismos. El crecimiento orgánico parece dar lugar a una mejor tecnología y a fundadores más ricos que el método del big bang. Si observas las tecnologías dominantes de hoy en día, descubrirás que la mayoría de ellas crecieron de forma orgánica.

Este patrón no solo se aplica a las empresas. También lo ves en la investigación patrocinada. Multics y Common Lisp fueron proyectos del big bang, y Unix y MacLisp fueron proyectos de crecimiento orgánico.

10 Rediseño

"La mejor escritura es la reescritura", escribió E. B. White. Todo buen escritor sabe esto, y es cierto también para el software. La parte más importante del diseño es el rediseño. Los lenguajes de programación, especialmente, no se rediseñan lo suficiente.

Para escribir buen software, debes tener en mente al mismo tiempo dos ideas opuestas. Necesitas la fe ingenua del joven hacker en sus habilidades, y al mismo tiempo el escepticismo del veterano. Tienes que ser capaz de pensar ¿qué tan difícil puede ser? con una mitad de tu cerebro mientras piensas nunca funcionará con la otra.

El truco es darse cuenta de que no hay una verdadera contradicción aquí. Quieres ser optimista y escéptico sobre dos cosas diferentes. Tienes que ser optimista sobre la posibilidad de resolver el problema, pero escéptico sobre el valor de cualquier solución que hayas tenido hasta ahora.

Las personas que hacen un buen trabajo a menudo piensan que lo que sea en lo que están trabajando no es bueno. Otros ven lo que han hecho y están llenos de asombro, pero el creador está lleno de preocupación. Este patrón no es una coincidencia: es la preocupación la que hizo que el trabajo fuera bueno.

Si puedes mantener la esperanza y la preocupación equilibradas, impulsarán un proyecto hacia adelante de la misma manera que tus dos piernas impulsan una bicicleta hacia adelante. En la primera fase del motor de innovación de dos ciclos, trabajas furiosamente 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 muy claramente. Pero mientras tu espíritu crítico no supere tu esperanza, podrás mirar tu sistema, admitidamente incompleto, y pensar, ¿qué tan difícil puede ser llegar al resto?, continuando así el ciclo.

Es complicado mantener equilibradas las dos 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 viejos, predomina el escepticismo, y ni siquiera se atreverán a asumir proyectos ambiciosos.

Cualquier cosa que puedas hacer para mantener el ciclo de rediseño en marcha es buena. La prosa puede reescribirse una y otra vez hasta que estés satisfecho con ella. Pero el software, como regla, no se rediseña lo suficiente. La prosa tiene lectores, pero el software tiene usuarios. Si un escritor reescribe un ensayo, las personas que leyeron la versión antigua son poco propensas a quejarse de que sus pensamientos se han visto interrumpidos por alguna incompatibilidad recién introducida.

Los usuarios son una espada de doble filo. Pueden ayudarte a mejorar tu lenguaje, pero también pueden disuadirte de mejorarlo. Así que elige tus usuarios con cuidado, y sé lento en aumentar su número. Tener usuarios es como la optimización: el curso sabio es retrasarlo. Además, como regla general, en cualquier momento puedes salirte con la tuya cambiando más de lo que piensas. Introducir cambios es como quitar un vendaje: el dolor es un recuerdo casi tan pronto como lo sientes.

Todo el mundo sabe que no es una buena idea tener un lenguaje diseñado por un comité. Los comités producen un mal diseño. Pero creo que el peor peligro de los comités es que interfieren con el rediseño. Es tanto trabajo introducir cambios que nadie quiere molestarse. Cualquier cosa que decida un comité tiende a quedarse así, incluso si a la mayoría de los miembros no les gusta.

Incluso un comité de dos se interpone en el rediseño. Esto sucede particularmente en las interfaces entre piezas de software escritas por dos personas diferentes. Para cambiar la interfaz, ambos tienen que acordar cambiarla al mismo tiempo. Y así, las interfaces tienden a no cambiar en absoluto, lo cual es un problema porque tienden a ser una de las partes más ad hoc de cualquier sistema.

Una solución aquí podría ser diseñar sistemas para que las interfaces sean horizontales en lugar de verticales, de modo que los módulos sean siempre estratos de abstracción apilados verticalmente. Entonces la interfaz tenderá a ser propiedad de uno de ellos. El nivel inferior de dos niveles será o bien un lenguaje en el que se escribe 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 Lisp

Todo esto implica que hay esperanza para un nuevo Lisp. Hay esperanza para cualquier lenguaje que dé a los hackers lo que quieren, incluyendo Lisp. Creo que hemos cometido un error al pensar que a los hackers les desagrada la rareza de Lisp. Esta reconfortante ilusión puede habernos impedido ver el verdadero problema con Lisp, o al menos con Common Lisp, que es que apesta para hacer lo que los hackers quieren hacer. Un lenguaje de hackers necesita bibliotecas potentes y algo para hackear. Common Lisp no tiene ninguna de las dos. Un lenguaje de hackers 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 verdadero lenguaje de hackers, 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 algún trabajo importante mejor que otros lenguajes.

La historia ofrece algo de aliento. Con el tiempo, los nuevos lenguajes de programación sucesivos han tomado más y más características de Lisp. Ya no queda mucho que copiar antes de que el lenguaje que has hecho sea Lisp. El último lenguaje de moda, Python, es un Lisp diluido 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 L. Pero mi conjetura es que no deberíamos tener miedo de llamar al nuevo Lisp Lisp. Lisp todavía tiene mucho respeto latente entre los mejores hackers, los que tomaron 6.001 y lo entendieron, por ejemplo. Y esos son los usuarios que necesitas ganar.

En "Cómo convertirse en un hacker", Eric Raymond describe Lisp como algo parecido al latín o al griego, un lenguaje que debes aprender como ejercicio intelectual, aunque en realidad no lo uses:

Lisp vale la pena aprender por la profunda experiencia de iluminación que tendrás cuando finalmente lo entiendas; esa experiencia te convertirá en un mejor programador durante el resto de tus días, incluso si nunca llegas a usar Lisp en sí mismo mucho.

Si no conociera Lisp, leer esto me haría hacer preguntas. Un lenguaje que me haría un mejor programador, si es que significa algo, significa un lenguaje que sería mejor para programar. Y esa es de hecho la implicación de lo que Eric está diciendo.

Mientras esa idea siga flotando, creo que los hackers estarán lo suficientemente receptivos a un nuevo Lisp, incluso si se llama Lisp. Pero este Lisp debe ser un lenguaje de hackers, como los Lisps clásicos de la década de 1970. Debe ser conciso, simple y hackeable. Y debe tener bibliotecas potentes para hacer lo que los hackers quieren hacer ahora.

En lo que respecta a las bibliotecas, creo que hay margen para superar a lenguajes como Perl y Python en su propio juego. Muchas de las nuevas aplicaciones que habrá que escribir en los próximos años serán aplicaciones basadas en servidores. No hay razón para que un nuevo Lisp no tenga bibliotecas de cadenas tan buenas como Perl, y si este nuevo Lisp también tuviera bibliotecas potentes para aplicaciones basadas en servidores, podría ser muy popular. Los verdaderos hackers no harán ascos a una nueva herramienta que les permita resolver problemas difíciles con unas pocas llamadas a la biblioteca. Recuerda, los hackers son vagos.

Podría ser una victoria aún mayor tener soporte de lenguaje central para aplicaciones basadas en servidores. 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 servidores también nos dan la respuesta a la pregunta de para qué se utilizará este nuevo Lisp para hackear. No haría daño mejorar Lisp como lenguaje de scripting para Unix. (Sería difícil empeorarlo). Pero creo que hay áreas donde los lenguajes existentes serían más fáciles de vencer. Creo que sería mejor seguir el modelo de Tcl, y suministrar el Lisp junto con un sistema completo para soportar aplicaciones basadas en servidores. Lisp es una opción natural para aplicaciones basadas en servidores. Los cierres léxicos proporcionan una forma de obtener el efecto de las subrutinas cuando la interfaz de usuario es sólo una serie de páginas web. Las S-expresiones se asignan muy bien al html, y las macros son buenas para generarlo. Es necesario que haya mejores herramientas para escribir aplicaciones basadas en servidores, y es necesario que haya un nuevo Lisp, y los dos funcionarían muy bien juntos.

12 El lenguaje soñado

A modo de resumen, intentemos describir el lenguaje soñado de los hackers. 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 de tu aplicación. Todo lo demás ya está hecho por ti.

La sintaxis del lenguaje es breve hasta la exageración. Nunca tienes que escribir un carácter innecesario, o incluso usar mucho la tecla Mayús.

Usando grandes abstracciones puedes escribir la primera versión de un programa muy rápidamente. Más tarde, cuando quieras optimizar, hay un realmente buen perfilador que te dice dónde debes centrar tu atención. Tú puedes hacer que los bucles internos sean increíblemente rápidos, incluso escribiendo código de bytes en línea si lo necesitas.

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 mirar mucho el manual. El manual es delgado y tiene pocas advertencias y calificaciones.

El lenguaje tiene un núcleo pequeño y bibliotecas potentes y altamente ortogonales que están tan cuidadosamente diseñadas como el lenguaje principal. Los bibliotecas funcionan todas bien juntas; todo en el lenguaje encaja juntas como las piezas de una cámara fina. Nada está obsoleto, o se mantiene por compatibilidad. El código fuente de todas las bibliotecas está fácilmente disponible. Es fácil hablar con el sistema operativo y con las aplicaciones escritas en otros lenguajes.

El lenguaje está construido en capas. Las abstracciones de nivel superior están construidas de una manera muy transparente a partir de abstracciones de nivel inferior, a las que puedes acceder si quieres.

No se te oculta nada que no tenga que serlo absolutamente. El lenguaje ofrece abstracciones solo como una forma de ahorrarte trabajo, en lugar de como una forma de decirte qué hacer. De hecho, el lenguaje te anima a ser un participante igualitario en su diseño. Puedes cambiar todo sobre él, incluyendo incluso su sintaxis, y cualquier cosa que escribas tiene, tanto como sea posible, el mismo estatus que lo que viene predefinido.

Notas

[1] Las macros muy cercanas a la idea moderna fueron propuestas por Timothy Hart en 1964, dos años después de que se publicara Lisp 1.5. 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 ambos.

[2] En Cuando el aire golpea tu cerebro, el neurocirujano Frank Vertosick recuerda una conversación en la que su residente principal, Gary, habla sobre la diferencia entre cirujanos e internistas ("pulgas"):

Gary y yo pedimos una pizza grande y encontramos un puesto libre. El jefe encendió un cigarrillo. "Mira a esas malditas pulgas, parloteando sobre alguna enfermedad que verán una vez en sus vidas. Ese es el problema con las pulgas, sólo les gusta lo raro. Odian sus casos de pan y mantequilla. Esa es la diferencia entre nosotros y las puñeteras pulgas. Verás, a nosotros nos encantan las grandes y jugosas hernias de disco lumbar, pero a ellos les da asco la hipertensión...."

Es difícil pensar en una hernia de disco lumbar como jugosa (excepto literalmente). Y sin embargo creo que sé lo que quieren decir. A menudo he tenido un bicho jugoso que perseguir. A alguien que no es programador le resultaría difícil imaginar que pudiera haber placer en un bug. Seguramente es mejor si todo funciona. En cierto modo, sí. Y sin embargo, hay, sin lugar a dudas, una satisfacción sombría en cazar ciertos tipos de errores.