¿Qué es exactamente la metaprogramación?

128

Estaba leyendo un artículo sobre TheServerSide sobre programación ployglot en la plataforma Java . Algunos comentarios en el artículo se refieren a la metaprogramación como la capacidad de generar código (quizás sobre la marcha).

Está metaprogramando la capacidad de generar código sobre la marcha o es la capacidad de inyectar métodos y atributos en objetos existentes en tiempo de ejecución (como lo que permiten algunos lenguajes dinámicos como Python, Ruby y Groovy).

Parag
fuente
77
Quizás te interese esta respuesta stackoverflow.com/questions/2565572/…
ewernli
@ewernli: ¡Esa respuesta es realmente mejor que cualquiera de las respuestas aquí!
JD

Respuestas:

100

La metaprogramación se refiere a una variedad de formas en que un programa tiene conocimiento de sí mismo o puede manipularse a sí mismo.

En lenguajes como C #, la reflexión es una forma de metaprogramación ya que el programa puede examinar información sobre sí mismo. Por ejemplo, devolver una lista de todas las propiedades de un objeto.

En lenguajes como ActionScript, puede evaluar funciones en tiempo de ejecución para crear nuevos programas como eval ("x" + i). DoSomething () afectaría a un objeto llamado x1 cuando yo sea 1 y x2 cuando yo sea 2.

Finalmente, otra forma común de metaprogramación es cuando el programa puede cambiarse a sí mismo de manera no trivial. LISP es bien conocido por esto y es algo por lo que Paul Graham defendió hace una década. Tendré que buscar algunos de sus ensayos específicos. Pero la idea es que el programa cambiaría otra parte del programa en función de su estado. Esto permite un nivel de flexibilidad para tomar decisiones en tiempo de ejecución que es muy difícil en los idiomas más populares hoy en día.

También vale la pena señalar que en los viejos tiempos de programación en ensamblaje directo, los programas que se alteraron en el tiempo de ejecución eran necesarios y muy comunes.

Del ensayo de Paul Graham "Lo que hizo diferente a Lisp" :

Muchos idiomas tienen algo llamado macro. Pero las macros de Lisp son únicas. Y lo creas o no, lo que hacen está relacionado con los paréntesis. Los diseñadores de Lisp no pusieron todos esos paréntesis en el lenguaje solo para ser diferentes. Para el programador de Blub, el código Lisp se ve raro. Pero esos paréntesis están ahí por una razón. Son la evidencia externa de una diferencia fundamental entre Lisp y otros idiomas.

El código Lisp está hecho de objetos de datos Lisp. Y no en el sentido trivial de que los archivos de origen contienen caracteres, y las cadenas son uno de los tipos de datos admitidos por el idioma. El código Lisp, después de ser leído por el analizador, está hecho de estructuras de datos que puede atravesar.

Si comprende cómo funcionan los compiladores, lo que realmente está sucediendo no es tanto que Lisp tenga una sintaxis extraña como que Lisp no tenga sintaxis. Usted escribe programas en los árboles de análisis que se generan dentro del compilador cuando se analizan otros idiomas. Pero estos árboles de análisis son totalmente accesibles para sus programas. Puedes escribir programas que los manipulen. En Lisp, estos programas se llaman macros. Son programas que escriben programas.

¿Programas que escriben programas? ¿Cuándo querrías hacer eso? No muy a menudo, si piensas en Cobol. Todo el tiempo, si piensas en Lisp. ¡Sería conveniente aquí si pudiera dar un ejemplo de una macro poderosa y decir allí! ¿Qué hay sobre eso? Pero si lo hiciera, parecería un galimatías para alguien que no conocía a Lisp; No hay espacio aquí para explicar todo lo que necesita saber para comprender lo que significa. En Ansi Common Lisp intenté mover las cosas lo más rápido que pude, y aun así no llegué a las macros hasta la página 160.

Pero creo que puedo dar una especie de argumento que podría ser convincente. El código fuente del editor de Viaweb era probablemente del 20-25% de las macros. Las macros son más difíciles de escribir que las funciones normales de Lisp, y se considera un mal estilo usarlas cuando no son necesarias. Entonces, cada macro en ese código está ahí porque tiene que estar. Lo que eso significa es que al menos el 20-25% del código en este programa está haciendo cosas que no puede hacer fácilmente en ningún otro idioma. Por más escéptico que pueda ser el programador de Blub sobre mis afirmaciones sobre los misteriosos poderes de Lisp, esto debería despertar su curiosidad. No estábamos escribiendo este código para nuestra propia diversión. Éramos una pequeña empresa, programando lo más duro posible para poner barreras técnicas entre nosotros y nuestros competidores.

Una persona sospechosa podría comenzar a preguntarse si había alguna correlación aquí. Una gran parte de nuestro código fue hacer cosas que son muy difíciles de hacer en otros idiomas. El software resultante hizo cosas que el software de nuestros competidores no podía hacer. Tal vez hubo algún tipo de conexión. Te animo a seguir ese hilo. Puede haber más en ese viejo cojeando sobre sus muletas de lo que parece.

DavGarcia
fuente
66
No te olvides de la metaprogramación de plantillas en C ++. La capacidad de ejecutar expresiones y tomar decisiones en tiempo de compilación, y hacer que los resultados se compilen estáticamente en el ejecutable final.
Remy Lebeau
1
Me sorprendió in order to put technical barriers between us and our competitorsy esto es correcto.
Evan Hu
44
Los programas que se manipulan a sí mismos son un subconjunto de todos los metaprogramas. La metaprogramación en general solo significa programas que manipulan programas.
JD
55

Gran pregunta Lamento mucho ver que ninguna de las respuestas actualmente responde a su pregunta correctamente. Quizás pueda ayudar ...

La definición de metaprogramación es realmente bastante simple: significa programas que manipulan programas.

Su respuesta aceptada dice programas que se manipulan a sí mismos. Esos son de hecho metaprogramas, pero son un subconjunto de todos los metaprogramas.

Todas:

  • Analizadores
  • Idiomas específicos del dominio (DSL)
  • Lenguajes específicos de dominio incorporado (EDSL)
  • Compiladores
  • Intérpretes
  • Reescritores de términos
  • El teorema prueba

son metaprogramas Entonces, el compilador GCC es un metaprograma, el intérprete de CPython es un metaprograma, el sistema de álgebra computacional de Mathematica es un metaprograma, el probador del teorema de Coq es un metaprograma y así sucesivamente.

Otras respuestas han afirmado que los metaprogramas son programas que generan otros programas. Esos son de hecho metaprogramas pero, nuevamente, son un subconjunto de todos los metaprogramas. La biblioteca de la Transformada de Fourier más rápida en el oeste (FFTW) es un ejemplo de dicho metaprograma. El código fuente está escrito principalmente en OCaml y genera bits de código C (llamados codelets) que se combinan para crear rutinas Fast Fourier Transform de alto rendimiento optimizadas para máquinas específicas. Esa biblioteca se usa realmente para proporcionar las rutinas FFT en Matlab. La gente ha estado escribiendo programas para generar métodos numéricos durante décadas, desde los primeros días de FORTRAN .

El primer lenguaje de programación que integró el soporte para la metaprogramación fue el lenguaje LISt Processor (LISP) a fines de la década de 1950. LISP 1.5 incluyó una serie de características que facilitaron la metaprogramación. En primer lugar, el tipo de datos centrales de LISP son listas anidadas, es decir, árboles (a (b c) d), lo que significa que cualquier código LISP puede expresarse de forma nativa como una estructura de datos. Esto se conoce como homoiconicidad. En segundo lugar, el código LISP se puede convertir en datos fácilmente usando QUOTE. Por ejemplo, (+ 1 2 3)agrega 1 + 2 + 3 y (QUOTE (+ 1 2 3))crea una expresión que agrega 1 + 2 + 3 cuando se evalúa. En tercer lugar, LISP proporcionó un evaluador meta-circular que le permite utilizar el intérprete o compilador de host para evaluar el código LISP en tiempo de ejecución, incluido el código LISP generado en tiempo de ejecución. Los descendientes de LISP incluyen Scheme y Clojure. En todos estos lenguajes, la metaprogramación se ve más comúnmente en forma de programas que se modifican a sí mismos, generalmente usando macros.

En la década de 1970, Robin Milner desarrolló un MetaLanguage (ML) que evolucionó a la familia ML de lenguajes de programación que incluye ML estándar y OCaml e influyó fuertemente en Haskell y F # . Estos idiomas facilitan la expresión de otros idiomas. En estos idiomas, los metaprogramas se ven más comúnmente en forma de lexers, analizadores, intérpretes y compiladores.

En 1994, Erwin Unruh descubrió que el sistema de plantillas C ++ estaba completo y podía usarse para ejecutar programas arbitrarios en tiempo de compilación . La metaprogramación de plantilla C ++ trajo la metaprogramación a las masas sin lavar que (ab) la usaron para muchas cosas diferentes, incluida la generación de métodos numéricos en la biblioteca Blitz ++ .

JD
fuente
33

Bueno, la metaprogramación es solo programación, pero es básicamente "escribir código que escribe código" .

La capacidad que mencionas cuando un programa puede observar y modificar su propia estructura y comportamiento se llama reflexión y es un tipo de metaprogramación.

Los lenguajes escritos dinámicamente tienen potentes funciones de reflexión en tiempo de ejecución, posibles gracias a la naturaleza interpretada de estos lenguajes ...

Los lenguajes tipados estáticos también tienen potentes técnicas de metaprogramación, por ejemplo, la metaprogramación de plantilla C ++ ...

CMS
fuente
14

Esta es solo mi opinión personal, que es probablemente la definición más liberal de metaprogramación.

Creo que incluye:

  1. Generación de código de compilación o generación de código de tiempo de ejecución (o ambos)
  2. Pensamiento Orientado a Aspectos o Programación Orientada a Aspectos
  3. Pensamiento SECO

Creo que puedes llegar usando cualquiera de estos y en combinación:

  1. Reflexión
  2. DSL (lenguajes específicos de dominio)
  3. Atributos (.NET) o Anotaciones (Java)
  4. Genéricos (.NET / Java)
  5. Plantillas (C ++)
  6. method_missing (Ruby)
  7. cierres / funciones de primera clase / delegados
  8. AOP - Programación Orientada a Aspectos
BuddyJoe
fuente
Respuesta muy concisa y reflexiva. me dio un buen menú de cosas para investigar. ¡gracias!
swyx
6

La metaprogramación es escribir un programa que genera otro programa. Esto es algo en lo que los lenguajes como Lisp son realmente buenos. Es mucho más fácil hacerlo en un lenguaje que admite macros reales (no macros C ++, sino más bien las que pueden manipular el código que generan) como Ruby, Lisp, Scheme, etc., que en un lenguaje como Java.

Una implementación es crear un "lenguaje específico de dominio", que es una forma de mejorar un lenguaje de programación para realizar una tarea específica. Puede ser increíblemente poderoso si se hace correctamente. Ruby on Rails es un buen ejemplo de este tipo de programación.

Si está interesado en explorar este método, consulte la Estructura e interpretación de los programas de computadora, que es uno de los libros fundamentales que cubre el tema.

Steve Rowe
fuente
5

La metaprogramación es la escritura de programas de computadora que escriben o manipulan otros programas (o ellos mismos) como sus datos, o que hacen parte del trabajo en tiempo de ejecución que de otro modo se realizaría en tiempo de compilación. En muchos casos, esto permite a los programadores hacer más en el mismo tiempo que tomarían para escribir todo el código manualmente, o les da a los programas una mayor flexibilidad para manejar eficientemente nuevas situaciones sin recompilación. ( Fuente )

Básicamente, es escribir código que genera más código, que se ejecuta para lograr algún objetivo. Esto generalmente se hace dentro del mismo idioma (usando javascript para crear una cadena de javascript, luego eval) o para emitir otro idioma (usando .NET para crear un archivo por lotes de Windows).

Masa en peligro de extinción
fuente
4

Wikipedia tiene un buen artículo sobre el tema. Uno no tiene que hacer modificaciones en tiempo de ejecución para que algo califique como metaprogramación. Por ejemplo, muchas personas usan plantillas de C ++ para realizar metaprogramaciones en tiempo de compilación.

Señor fooz
fuente