Loading...

LA CONCISIÓN ES PODER

Original

May 2002

"La cantidad de significado comprimido en un pequeño espacio por signos algebraicos, es otra circunstancia que facilita los razonamientos a los que estamos acostumbrados a llevar a cabo con su ayuda".

  • Charles Babbage, citado en la conferencia de Iverson por el premio Turing

En la discusión sobre las cuestiones planteadas por Revenge of the Nerds en la lista de correo de LL1, Paul Prescod escribió algo que se me quedó grabado.

El objetivo de Python es la regularidad y la legibilidad, no la concisión.

A primera vista, esto parece una afirmación bastante condenatoria sobre un lenguaje de programación. Por lo que puedo decir, la concisión = poder. Si es así, entonces sustituyendo, obtenemos

El objetivo de Python es la regularidad y la legibilidad, no el poder.

y esto no parece una compensación (si es que es una compensación) que quieras hacer. No está lejos de decir que el objetivo de Python no es ser efectivo como lenguaje de programación.

¿La concisión = poder? Esto me parece una pregunta importante, quizás la pregunta más importante para cualquier persona interesada en el diseño de lenguajes, y una que sería útil enfrentar directamente. Todavía no estoy seguro de que la respuesta sea un simple sí, pero parece una buena hipótesis para empezar.

Hipótesis

Mi hipótesis es que la concisión es poder, o está lo suficientemente cerca que excepto en ejemplos patológicos puedes tratarlas como idénticas.

Me parece que la concisión es para lo que sirven los lenguajes de programación. Las computadoras estarían igualmente felices de que les dijeran qué hacer directamente en lenguaje de máquina. Creo que la principal razón por la que nos tomamos la molestia de desarrollar lenguajes de alto nivel es para obtener apalancamiento, de modo que podamos decir (y lo que es más importante, pensar) en 10 líneas de un lenguaje de alto nivel lo que requeriría 1000 líneas de lenguaje de máquina. En otras palabras, el principal objetivo de los lenguajes de alto nivel es hacer que el código fuente sea más pequeño.

Si el código fuente más pequeño es el propósito de los lenguajes de alto nivel, y el poder de algo es lo bien que logra su propósito, entonces la medida del poder de un lenguaje de programación es qué tan pequeño lo hace tus programas.

Por el contrario, un lenguaje que no hace que tus programas sean pequeños está haciendo un mal trabajo de lo que se supone que deben hacer los lenguajes de programación, como un cuchillo que no corta bien, o una impresión que es ilegible.

Métricas

¿Pequeño en qué sentido? La medida más común del tamaño del código es líneas de código. Pero creo que esta métrica es la más común porque es la más fácil de medir. No creo que nadie realmente crea que es la verdadera prueba de la longitud de un programa. Diferente los lenguajes tienen diferentes convenciones sobre cuánto debes poner en una línea; en C muchas líneas no tienen nada más que un delimitador o dos.

Otra prueba fácil es el número de caracteres en un programa, pero esto tampoco es muy bueno; algunos lenguajes (Perl, por ejemplo) simplemente utilizan identificadores más cortos que otros.

Creo que una mejor medida del tamaño de un programa sería el número de elementos, donde un elemento es cualquier cosa que sería un nodo distinto si dibujaras un árbol que representa el código fuente. El nombre de una variable o función es un elemento; un entero o un número de punto flotante es un elemento; un segmento de texto literal es un elemento; un elemento de un patrón, o una directiva de formato, es un elemento; un nuevo bloque es un elemento. Hay casos límite (¿es -5 dos elementos o uno?) pero creo que la mayoría de ellos son los mismos para todos los lenguajes, por lo que no afectan mucho las comparaciones.

Esta métrica necesita ser completada y podría requerir interpretación en el caso de lenguajes específicos, pero creo que intenta medir lo correcto, que es el número de partes que tiene un programa. Creo que el árbol que dibujarías en esto el ejercicio es lo que tienes que hacer en tu cabeza para concebir el programa, por lo que su tamaño es proporcional a la cantidad de trabajo que tienes que hacer para escribirlo o leerlo.

Diseño

Este tipo de métrica nos permitiría comparar diferentes lenguajes, pero ese no es, al menos para mí, su principal valor. El principal valor de la prueba de concisión es como una guía para diseñar lenguajes. La comparación más útil entre lenguajes es entre dos variantes potenciales del mismo idioma. ¿Qué puedo hacer en el lenguaje para hacer que los programas sean más cortos?

Si la carga conceptual de un programa es proporcional a su complejidad, y un programador dado puede tolerar una carga conceptual fija, entonces esto es lo mismo que preguntar, ¿qué puedo hacer para permitir que los programadores obtengan más trabajo hecho? Y eso me parece idéntico a preguntar, ¿cómo puedo diseñar un buen lenguaje?

(Por cierto, nada hace más obvio que la vieja frase hecha "todos los idiomas son equivalentes" es falsa que diseñar lenguajes. Cuando estás diseñando un nuevo lenguaje, estás constantemente comparando dos idiomas, el idioma si hice x, y si no, para decidir cuál es mejor. Si esta fuera realmente una pregunta sin sentido, podrías lanzar una moneda).

Apuntar a la concisión parece una buena manera de encontrar nuevas ideas. Si puedes hacer algo que hace que muchos diferentes programas sean más cortos, probablemente no sea una coincidencia: tienes probablemente has descubierto una nueva abstracción útil. Incluso podrías poder escribir un programa para ayudar buscando código fuente para patrones repetidos. Entre otros idiomas, aquellos con una reputación de concisión serían los que buscarían nuevas ideas: Forth, Joy, Icon.

Comparación

La primera persona que escribió sobre estos temas, que yo sepa, fue Fred Brooks en el Mythical Man Month. Él escribió que los programadores parecían generar aproximadamente la misma cantidad de código por día independientemente del lenguaje. Cuando leí esto por primera vez a principios de mis veinte años, fue una gran sorpresa para mí y parecía tener enormes implicaciones. Significaba que (a) la única forma de obtener software escrito más rápido era usar un lenguaje más conciso, y (b) alguien que se tomó la molestia de hacer esto podría dejar atrás a los competidores que no lo hicieron.

La hipótesis de Brooks, si es cierta, parece estar en el corazón mismo de la piratería. En los años transcurridos desde entonces, he prestado mucha atención a cualquier evidencia que pudiera obtener sobre la cuestión, desde estudios formales hasta anécdotas sobre individuos proyectos. No he visto nada que lo contradiga.

Aún no he visto pruebas que me parezcan concluyentes, y no espero hacerlo. Estudios como la comparación de lenguajes de programación de Lutz Prechelt, mientras generando el tipo de resultados que esperaba, tienden a usar problemas que son demasiado cortos para ser pruebas significativas. Una mejor prueba de un lenguaje es lo que sucede en programas que tardan un mes en escribirse. Y el único prueba real, si crees como yo que el principal propósito de un lenguaje es ser bueno para pensar (en lugar de solo decirle a una computadora qué hacer una vez que lo hayas pensado) es qué cosas nuevas puedes escribir en él. Así que cualquier comparación de lenguajes donde tengas que cumplir con una especificación predefinida está probando un poco lo incorrecto cosa.

La verdadera prueba de un lenguaje es qué tan bien puedes descubrir y resolver nuevos problemas, no qué tan bien puedes usarlo para resolver un problema que alguien más tiene ya formulado. Estos dos son criterios bastante diferentes. En el arte, medios como el bordado y el mosaico funcionan bien si sabes de antemano lo que quieres hacer, pero son absolutamente pésimos si no lo haces. Cuando quieres descubrir la imagen mientras la creas, como tienes que hacer con cualquier cosa tan compleja como una imagen de un persona, por ejemplo, necesitas usar un medio más fluido como el lápiz o tinta china o pintura al óleo. Y, de hecho, la forma en que se hacen los tapices y los mosaicos en la práctica es hacer una pintura primero y luego copiarla. (La palabra "boceto" se utilizó originalmente para describir una pintura destinada a este propósito).

Lo que esto significa es que es poco probable que tengamos comparaciones precisas del poder relativo de los lenguajes de programación. Tendremos comparaciones precisas, pero no precisas. En particular, estudios explícitos con el propósito de comparar idiomas, porque probablemente usarán problemas pequeños, y necesariamente usarán problemas predefinidos, tenderán a subestimar el poder de los lenguajes más poderosos.

Los informes de campo, aunque necesariamente serán menos precisos que los estudios "científicos", es probable que sean más significativos. Por ejemplo, Ulf Wiger de Ericsson hizo un estudio que concluyó que Erlang era 4-10x más conciso que C++, y proporcionalmente más rápido para desarrollar software en:

Las comparaciones entre los proyectos de desarrollo internos de Ericsson indican similar productividad de línea/hora, incluidas todas las fases del desarrollo de software, bastante independientemente de qué lenguaje (Erlang, PLEX, C, C++ o Java) fue utilizado. Lo que diferencia a los diferentes idiomas se convierte entonces en el código fuente volumen.

El estudio también trata explícitamente un punto que fue solo implícito en el libro de Brooks (ya que midió líneas de código depurado): los programas escritos en lenguajes más potentes tienden a tener menos errores. Eso se convierte en un fin en sí mismo, posiblemente más importante que el programador productividad, en aplicaciones como conmutadores de red.

La prueba de sabor

En última instancia, creo que tienes que confiar en tu instinto. ¿Qué se siente como programar en el idioma? Creo que la forma de encontrar (o diseñar) el mejor lenguaje es volverse hipersensible a qué tan bien un lenguaje te permite pensar, luego elige/diseña el lenguaje que se siente mejor. Si alguna característica del lenguaje es incómoda o restrictiva, no te preocupes, tú sabrás de eso.

Tal hipersensibilidad tendrá un costo. Descubrirás que no puedes soportar programar en lenguajes torpes. Encuentro insoportablemente restrictivo programar en lenguajes sin macros, al igual que alguien que usó para escribir dinámicamente encuentra insoportablemente restrictivo tener que volver a programar en un idioma en el que tienes que declarar el tipo de cada variable, y no puede hacer una lista de objetos de diferentes tipos.

No soy el único. Conozco muchos hackers de Lisp a quienes les ha pasado esto. De hecho, la medida más precisa del poder relativo de la programación los idiomas pueden ser el porcentaje de personas que conocen el idioma que tomará cualquier trabajo donde pueda usar ese idioma, independientemente del dominio de aplicación.

Restrictividad

Creo que la mayoría de los hackers saben lo que significa que un idioma se sienta restrictivo. ¿Qué está pasando cuando sientes eso? Creo que es la misma sensación que obtienes cuando la calle que quieres tomar está bloqueada y tienes que tomar un largo desvío para llegar a donde querías ir. Hay algo que quieres decir, y el idioma no te deja.

Lo que realmente está pasando aquí, creo, es que un lenguaje restrictivo es uno que no es lo suficientemente conciso. El problema no es simplemente que no puedas decir lo que planeabas decir. Es que el desvío que el idioma te hace tomar es más largo. Prueba este experimento mental. Supongamos que hubiera algún programa que querías escribir, y el idioma no te permitiría expresarlo de la forma en que planeabas, sino que te obligó a escribir el programa de otra manera que fue más corta. Para mí al menos, eso no se sentiría muy restrictivo. Sería como si la calle que querías tomar estaba bloqueada, y el policía en la intersección te dirige a un atajo en lugar de a un desvío. ¡Genial!

Creo que la mayoría (noventa por ciento?) de la sensación de restrictividad proviene de verse obligado a hacer el programa que escribas en el idioma más largo que uno que tengas en tu cabeza. La restrictividad es principalmente la falta de concisión. Entonces, cuando un lenguaje se siente restrictivo, lo que (principalmente) significa es que no es lo suficientemente conciso, y cuando un lenguaje no es conciso, se sentirá restrictivo.

Legibilidad

La cita con la que comencé menciona otras dos cualidades, la regularidad y la legibilidad. No estoy seguro de qué es la regularidad, o qué ventaja, en su caso, el código que es regular y legible tiene sobre el código que es meramente legible. Pero creo que sé lo que se entiende por legibilidad, y creo que también está relacionado con la concisión.

Tenemos que tener cuidado aquí para distinguir entre la legibilidad de una línea de código individual y la legibilidad de todo el programa. Es el segundo el que importa. Estoy de acuerdo en que una línea de Basic es probable que sea más legible que una línea de Lisp. Pero un programa escrito en Basic es va a tener más líneas que el mismo programa escrito en Lisp (especialmente una vez que cruces a Greenspunland). El el esfuerzo total de leer el programa Basic seguramente será mayor.

esfuerzo total = esfuerzo por línea x número de líneas

No estoy tan seguro de que la legibilidad sea directamente proporcional a la concisión como estoy seguro de que el poder lo es, pero ciertamente la concisión es un factor (en el sentido matemático; véase la ecuación anterior) en la legibilidad. Por lo que incluso puede que no tenga sentido decir que el objetivo de un lenguaje es la legibilidad, no la concisión; podría ser como decir que el objetivo era la legibilidad, no la legibilidad.

Lo que significa la legibilidad por línea, para el usuario que encuentra el lenguaje por primera vez, es que el código fuente parecerá no amenazante. Entonces la legibilidad por línea podría ser una buena decisión de marketing, incluso si es una mala decisión de diseño. Es isomorfo a la técnica muy exitosa de dejar que la gente pague en cuotas: en lugar de asustarlos con una alta precio inicial, les dices el bajo pago mensual. Los planes de pago son una pérdida neta para el comprador, sin embargo, como la mera legibilidad por línea probablemente es para el programador. El comprador va a hacer muchas de esos pagos bajos, bajos; y el programador va a leer muchas de esas líneas individualmente legibles.

Esta compensación es anterior a los lenguajes de programación. Si estás acostumbrado a leer novelas y artículos de periódicos, tu primera experiencia de leer un matemático el papel puede ser desalentador. Podría tardar media hora en leer una sola página. Y sin embargo, estoy bastante seguro de que la notación no es el problema, aunque puede parecerlo. El artículo de matemáticas es difícil de leer porque las ideas son difíciles. Si expresaras las mismas ideas en prosa (como los matemáticos tenían que hacerlo antes de que desarrollaran notaciones concisas), no serían más fáciles de leer, porque el artículo crecería hasta el tamaño de un libro.

Hasta qué punto?

Varias personas han rechazado la idea de que la concisión = poder. Creo que sería más útil, en lugar de simplemente argumentar que son iguales o no lo son, preguntar: ¿hasta qué punto la concisión = poder? Porque está claro que la concisión es una gran parte de lo que son para los lenguajes de más alto nivel. Si no es todo para lo que son, entonces ¿para qué más son, y qué tan importantes, relativamente, son estos otras funciones?

No propongo esto solo para hacer el debate más civilizado. Realmente quiero saber la respuesta. ¿Cuándo, si es que alguna vez, un idioma es demasiado conciso para su propio bien?

La hipótesis con la que comencé fue que, excepto en ejemplos patológicos, creía que la concisión podría considerarse idéntica al poder. Qué quería decir es que en cualquier idioma que alguien diseñara, ellos serían idénticos, pero que si alguien quisiera diseñar un idioma explícitamente para refutar esta hipótesis, probablemente podría hacerlo. Yo ni siquiera estoy seguro de eso, en realidad.

Lenguajes, no programas

Debemos tener claro que estamos hablando de la concisión de lenguajes, no de programas individuales. Ciertamente es posible que se escriban programas individuales demasiado densamente.

Escribí sobre esto en On Lisp. Una macro compleja puede tener que guardar muchas veces su propia longitud para justificarse. Si escribiendo alguna macro peluda podría ahorrarte diez líneas de código cada vez que la uses, y la macro es en sí misma diez líneas de código, entonces obtienes un ahorro neto en líneas si la usas más de una vez. Pero eso podría seguir siendo un mal movimiento, porque las definiciones de macro son más difíciles de leer que el código ordinario. Tú es posible que tengas que usar la macro diez o veinte veces antes de que genere un neto mejora en la legibilidad.

Estoy seguro de que todos los idiomas tienen esas compensaciones (aunque sospecho que las apuestas son más altas a medida que el idioma se vuelve más poderoso). Todo programador debe haber visto código que alguna persona inteligente ha hecho marginalmente más corto utilizando trucos de programación dudosos.

Así que no hay discusión sobre eso, al menos, no de mi parte. Individual los programas ciertamente pueden ser demasiado concisos para su propio bien. La pregunta es, ¿puede un lenguaje serlo? ¿Puede un lenguaje obligar a los programadores a escribir código que sea corto (en elementos) a expensas de la legibilidad general?

Una razón por la que es difícil imaginar que un lenguaje sea demasiado conciso es que si hubiera alguna forma excesivamente compacta de expresar algo, habría probablemente también una forma más larga. Por ejemplo, si sintieras que los programas Lisp que usan muchas macros o funciones de orden superior fueran demasiado densas, pudieras, si preferido, escribir código que fuera isomorfo a Pascal. Si tú no quieres expresar factorial en Arc como una llamada a una función de orden superior


(rec zero 1 * 1-)

también puedes escribir una definición recursiva:


(rfn fact (x) (if (zero x) 1 (* x (fact (1- x)))))

Aunque no se me ocurre ningún ejemplo de memoria, me interesa la cuestión de si un lenguaje podría ser demasiado conciso. ¿Hay idiomas que te obligan a escribir código de una manera que es desgarrada e incomprensible? Si alguien tiene ejemplos, me encantaría verlos.

(Recordatorio: Lo que estoy buscando son programas que sean muy densos de acuerdo con la métrica de "elementos" esbozada anteriormente, no solo programas que son cortos porque los delimitadores se pueden omitir y todo tiene un nombre de un carácter).