¿Cómo ha cambiado el ensayo de Paul Graham “Superando los promedios” desde que fue escrito?

Los puntos de PG son igualmente válidos hoy. Sin embargo, creo que es fácil interpretar erróneamente que los puntos solo se aplican a LISP. El argumento de PG es sobre el poder de la metaprogramación y cómo la programación altamente apalancada permite un desarrollo más rápido de órdenes de magnitud. El poder de los programas que escriben programas y los programas que ejecutan programas.

Es cierto que hay pocos lenguajes que expresan metaprogramación tan elegante y directamente dentro del lenguaje como LISP (y ahora Clojure). Algunos otros lenguajes que lo prueban son OCaml, Tick-C, D y Nemerle.

Sin embargo, la metaprogramación es un concepto que tiene muchos tonos de gris. El preprocesador C, las plantillas C ++ y las plantillas T4 permiten ciertas formas de metaprogramación. Ciertos tipos de metaprogramación se pueden lograr con Javascript, Python, Ruby o el protocolo de metaobjetos Smalltalk y eval, o las clases de tipos Haskell. Los compiladores IDL, como Thrift y Google Protocol Buffers son un caso específico de metaprogramación. El compilador de ADN / ARN de Blender es meta-programación. Usar metaprogramación es una tuerca más compleja que “usar LISP”.

¿Cuáles son algunas diferencias entre estos ejemplos y la metaprogramación LISP?

Si bien el compilador Thrift es un programa que genera programas, su código es posiblemente más complejo que las macros LISP, y no está escrito en el mismo lenguaje que el resto del programa, a menos que esté utilizando Java. Incluso si estás en Java hasta las rodillas, si quieres cambiar el compilador de segunda mano, tienes que cambiar de marcha. Si desea generar un tipo diferente de código, debe elegir una estrategia de metacompilador diferente. Dicho esto, el compilador Thrift también genera código en muchos idiomas.

Los lenguajes compilados estáticamente, como C y C ++, no admiten de forma nativa la evaluación del código en tiempo de ejecución, ni conservan suficiente información de tipo para interactuar directamente con sus datos. Esto significa trabajo adicional si se exponen esos datos a un intérprete en tiempo de ejecución.

¿Esto significa que todos deberíamos estar usando LISP? No. Todos deberíamos estar usando meta-programación.

LISP es ideal para algunos proyectos, pero también tiene compensaciones que no siempre son convenientes o agradables.

LISP es de tipo dinámico, y por lo tanto viene con los beneficios y desventajas de otros lenguajes similares como Python, Ruby y Javascript. En particular, los programas con tipos complejos o API complejas no tienen el beneficio de las declaraciones de tipo o la verificación de tipo en tiempo de compilación. Esto puede hacer que el código más grande sea más frágil y ejerza más presión sobre las pruebas unitarias y las pruebas qa. También hace que el código sea menos legible, ya que no es evidente qué tipos aparecen en cada variable al mirar el código. Este problema se agrava cuando un gran número de desarrolladores necesitan confiar o cambiar el código.

LISP no es la opción más rápida, cuando el rendimiento es importante. Algunos programas se benefician enormemente del control estricto del diseño de datos para la eficiencia de la memoria caché. Algunos programas no pueden permitirse los gastos generales y la parada mundial de la recolección de basura.

A veces, conectar LISP a muchas bibliotecas complejas escritas en otros idiomas puede ser un desafío. Clojure puede ayudar con esto, haciendo que las bibliotecas de Java estén disponibles, sin embargo, cuando se utilizan bibliotecas de sistema de nivel C, encontrar, escribir o mantener interfaces de envoltura de funciones foráneas puede ser un trabajo adicional y puede tener inconvenientes en el rendimiento.

¿Qué suplica responder a la pregunta, cómo podemos hacer eficientemente la meta-programación fuera de LISP?

Ahora es muy común ver lenguajes de script como Lua, Javascript o incluso LISP, integrados en programas C o C ++. Por ejemplo, en la programación de juegos en 3D y en los navegadores web Chrome y Firefox. Si bien la incorporación de un lenguaje de script requiere un trabajo adicional para hacer lo que LISP puede hacer directamente, los programas resultantes a menudo son muchas veces más rápidos de lo que serían si estuvieran codificados completamente en LISP. La abstracción explícita de ciertas variables y conceptos en el código del script también es a menudo deseable, y existiría también en una versión totalmente codificada por LISP.

Una gran cantidad de software no codificado por LISP incorpora metaprogramación en tiempo de compilación a través de generadores de código. Ya hemos mencionado algunas instancias específicas arriba, como Thrift, sin embargo, también hay motores genéricos de plantillas de código en uso: T4 y XML / XSLT son dos ejemplos principales. Si bien esto tiene algunas desventajas en relación con las macros LISP, también tiene ventajas. Funcionan con cualquier idioma, incluidos aquellos con escritura estática y alto rendimiento. También producen una separación entre macros y código que puede ser útil para comprender situaciones macro difíciles.

En resumen, los conceptos de programación de alto apalancamiento, como la metaprogramación, son tan importantes hoy como lo fueron en 2001. LISP (y ahora Clojure) todavía ofrecen algunas de las metaprogramaciones más elegantes. Cuando no son adecuados para un proyecto, hay una gran variedad de técnicas para la metaprogramación en otros idiomas.