La metaprogramación es una técnica de programación informática en la que los programas informáticos tienen la capacidad de tratar a otros programas como si fueran sus datos . Esto significa que un programa puede diseñarse para leer, generar, analizar o transformar otros programas, e incluso modificarse a sí mismo, mientras se ejecuta. [ 1 ] [ 2 ] En algunos casos, esto permite a los programadores minimizar el número de líneas de código para expresar una solución, reduciendo así el tiempo de desarrollo. [ 3 ] También proporciona a los programas mayor flexibilidad para manejar eficientemente nuevas situaciones sin necesidad de recompilar.
La metaprogramación puede utilizarse para trasladar cálculos del tiempo de ejecución al tiempo de compilación , generar código a partir de cálculos realizados en tiempo de compilación y habilitar código automodificable . La capacidad de un lenguaje de programación para ser su propio metalenguaje permite la programación reflexiva y se denomina reflexión . [ 4 ] La reflexión es una valiosa característica del lenguaje que facilita la metaprogramación.
La metaprogramación fue popular en las décadas de 1970 y 1980, utilizando lenguajes de procesamiento de listas como Lisp . El hardware de las máquinas Lisp cobró cierta relevancia en la década de 1980 y permitió el desarrollo de aplicaciones capaces de procesar código. Estas aplicaciones se utilizaban con frecuencia en el ámbito de la inteligencia artificial .
Aproches
La metaprogramación permite a los desarrolladores escribir programas y desarrollar código que se ajusta al paradigma de programación genérica . También resulta muy útil que el propio lenguaje de programación sea un tipo de dato de primera clase (como en Lisp , Prolog , SNOBOL o Rebol ); esto se conoce como homoiconicidad . La programación genérica aprovecha la metaprogramación dentro de un lenguaje al permitir escribir código sin preocuparse por especificar los tipos de datos, ya que estos se pueden proporcionar como parámetros al utilizarse.
La metaprogramación suele funcionar de una de tres maneras. [ 5 ]
- El primer enfoque consiste en exponer los detalles internos del sistema de tiempo de ejecución (motor) al código de programación a través de interfaces de programación de aplicaciones (API), como la del emisor de lenguaje intermedio común (CIL) de .NET .
- El segundo enfoque consiste en la ejecución dinámica de expresiones que contienen comandos de programación, a menudo compuestos por cadenas de caracteres, pero también pueden provenir de otros métodos que utilizan argumentos o contexto, como JavaScript . [ 6 ] Por lo tanto, "los programas pueden escribir programas". Si bien ambos enfoques pueden utilizarse en el mismo lenguaje, la mayoría de los lenguajes tienden a inclinarse hacia uno u otro.
- El tercer enfoque consiste en prescindir por completo del lenguaje. Los sistemas de transformación de programas de propósito general, como los compiladores , que aceptan descripciones de lenguajes y realizan transformaciones arbitrarias sobre ellos, son implementaciones directas de metaprogramación general. Esto permite aplicar la metaprogramación a prácticamente cualquier lenguaje de destino, independientemente de si este posee o no capacidades de metaprogramación propias. Esto se puede observar en Scheme y cómo permite superar algunas limitaciones de C mediante el uso de construcciones propias del lenguaje Scheme para extender C. [ 7 ]
Lisp es probablemente el lenguaje por excelencia con funcionalidades de metaprogramación, tanto por su precedencia histórica como por la simplicidad y potencia de su metaprogramación. En la metaprogramación de Lisp, el operador de descomillas (normalmente una coma) introduce código que se evalúa en el momento de la definición del programa en lugar de en el tiempo de ejecución. El lenguaje de metaprogramación es, por lo tanto, idéntico al lenguaje de programación anfitrión, y las rutinas de Lisp existentes pueden reutilizarse directamente para la metaprogramación si se desea. Este enfoque se ha implementado en otros lenguajes mediante la incorporación de un intérprete en el programa, que trabaja directamente con los datos del programa. Existen implementaciones de este tipo para algunos lenguajes de alto nivel comunes, como Pascal Script para Object Pascal de RemObjects .
Usos
Generación de código
Un ejemplo sencillo de metaprograma es este script de shell POSIX , que es un ejemplo de programación generativa :
#!/bin/sh # metaprograma echo '#!/bin/sh' > programa para i en $( seq 992 ) hacer echo "echo $i " >> programa hecho chmod +x programa Este script (o programa) genera un nuevo programa de 993 líneas que imprime los números del 1 al 992. Esto es solo un ejemplo de cómo usar código para escribir más código; no es la forma más eficiente de imprimir una lista de números. Sin embargo, un programador puede escribir y ejecutar este metaprograma en menos de un minuto, y habrá generado más de 1000 líneas de código en ese lapso.
Un quine es un tipo especial de metaprograma que genera su propio código fuente como resultado. Los quines suelen tener únicamente interés recreativo o teórico.
No toda la metaprogramación implica programación generativa. Si los programas se pueden modificar en tiempo de ejecución o si se dispone de compilación incremental (como en C# , Forth , Frink , Groovy , JavaScript , Lisp , Elixir , Lua , Nim , Perl , PHP , Python , Rebol , Ruby , Rust , R , SAS , Smalltalk y Tcl ), entonces se pueden utilizar técnicas para realizar metaprogramación sin generar código fuente.
Un estilo de enfoque generativo consiste en emplear lenguajes específicos de dominio (DSL). Un ejemplo bastante común del uso de DSL implica la metaprogramación generativa: lex y yacc , dos herramientas utilizadas para generar analizadores léxicos y sintácticos , permiten al usuario describir el lenguaje mediante expresiones regulares y gramáticas libres de contexto , e incorporan los algoritmos complejos necesarios para analizar el lenguaje de manera eficiente.
Instrumentación de código
Una de las aplicaciones de la metaprogramación es la instrumentación de programas para realizar análisis dinámicos de programas .
Desafíos
Algunos argumentan que existe una curva de aprendizaje pronunciada para aprovechar al máximo las características de la metaprogramación. [ 8 ] Dado que la metaprogramación ofrece mayor flexibilidad y configurabilidad en tiempo de ejecución, su mal uso o uso incorrecto puede generar errores inesperados e injustificados que pueden ser extremadamente difíciles de depurar para un desarrollador promedio. Puede introducir riesgos en el sistema y hacerlo más vulnerable si no se utiliza con cuidado. Algunos de los problemas comunes que pueden surgir debido al uso incorrecto de la metaprogramación son la incapacidad del compilador para identificar parámetros de configuración faltantes, y los datos inválidos o incorrectos pueden generar excepciones desconocidas o resultados diferentes. [ 9 ] Debido a esto, algunos creen [ 8 ] que solo los desarrolladores altamente capacitados deberían trabajar en el desarrollo de características que implementen la metaprogramación en un lenguaje o plataforma, y que los desarrolladores promedio deben aprender a usar estas características como parte de la convención.
Usos en lenguajes de programación
Macrosistemas
ensambladores macro
El IBM/360 y sus derivados contaban con potentes herramientas de ensamblaje de macros que se utilizaban con frecuencia para generar programas completos en lenguaje ensamblador o secciones de programas (para diferentes sistemas operativos, por ejemplo). Las macros incluidas en el sistema de procesamiento de transacciones CICS contenían macros de ensamblador que generaban sentencias COBOL como paso previo al procesamiento.
Otros ensambladores, como MASM , también admiten macros.
Metaclases
Las metaclases son proporcionadas por los siguientes lenguajes de programación:
Metaprogramación de plantillas
- C , usando macros X
- C++ , usando plantillas [ 11 ]
- D
- Common Lisp , Scheme y la mayoría de los dialectos de Lisp mediante el uso del operador quasiquote ("backquote"). [ 12 ]
- Nim
Metaprogramación por etapas
Tipos dependientes
El uso de tipos dependientes permite demostrar que el código generado nunca es inválido. [ 15 ] Sin embargo, este enfoque es vanguardista y rara vez se encuentra fuera de los lenguajes de programación de investigación.
Implementaciones
La lista de sistemas de metaprogramación destacados se mantiene en Lista de sistemas de transformación de programas .
Véase también
- Tejedor de aspectos
- Comparación de herramientas de generación de código
- Ejecución de funciones en tiempo de compilación
- Programación genética
- Homoiconicidad
- Simulador de conjunto de instrucciones
- Lenguaje interpretado
- Aprendizaje automático
- Metacompilador
- Metaobjeto
- Evaluación parcial
- Programación reflexiva , también reflexión en tiempo de compilación
- Autointérprete
- Código automodificable
- Generación de código fuente
- Transcompilador (también conocido como transpilación)
- Integración a muy gran escala
- Problema de parada
Referencias
- ↑ Sondergaard, Harald (2013). "Curso sobre análisis y transformación de programas" . Recuperado el 18 de septiembre de 2014 .
- ↑ Czarnecki, Krzysztof ; Eisenecker, Ulrich W. (2000). Programación Generativa . Addison Wesley. ISBN 0-201-30977-7.
- ↑ Walker, Max. "El arte de la metaprogramación en Java" . New Circle . Consultado el 28 de enero de 2014 .
- ↑ Krauss, Aaron. "Conceptos de programación: introspección y reflexión de tipos" . Archivado del original el 10 de marzo de 2016. Recuperado el 10 de marzo de 2016 .
- ↑ Joshi, Prateek (5 de abril de 2014). "¿Qué es la metaprogramación? – Parte 2/2" . Perpetual Enigma . Recuperado el 14 de agosto de 2014 .
- ↑ Por ejemplo, instance_eval en Ruby acepta una cadena o una función anónima. "Clase BasicObject Ruby 3.5" .
- ↑ "El arte de la metaprogramación" . IBM .
- 1 2 Bicking, Ian. "El desafío de la metaprogramación" . IanBicking.org . Consultado el 21 de septiembre de 2016 .
- ↑ Terry, Matt (21 de agosto de 2013). "Cuidado con la metaprogramación" . Medium.com . Medium Corporation . Consultado el 21 de agosto de 2014 .
- ↑ Medianteel "Protocolo de Metaobjetos" del Sistema de Objetos de Common Lisp
- ↑ "Metaprogramación con plantillas de C++" . aszt.inf.elte.hu. Consultado el 23 de julio de 2022 .
- ↑ Lisp (lenguaje de programación) "Formas autoevaluables y comillas", operador de cuasi-comillas.
- ↑ "LMS: Generación de programas y compiladores integrados en Scala" . scala-lms.github.io . Consultado el 6 de diciembre de 2017 .
- ↑ Rompf, Tiark; Odersky, Martin (junio de 2012). "Estructura modular ligera: un enfoque pragmático para la generación de código en tiempo de ejecución y DSL compilados" . Communications of the ACM . 55 (6): 121–130 . doi : 10.1145/2184319.2184345 . ISSN 0001-0782 . S2CID 52898203 .
- ↑ Chlipala, Adam (junio de 2010). "Ur: metaprogramación con tipado estático y cálculo de registros a nivel de tipo" (PDF) . ACM SIGPLAN Notices . PLDI '10. 45 (6): 122– 133. doi : 10.1145/1809028.1806612 . Consultado el 29 de agosto de 2012 .
Enlaces externos
- c2.com Wiki: artículo sobre metaprogramación
- Metaprogramación en la Wiki de Transformación de Programas
- Generación de código versus metaprogramación
- "Solenoid" : El primer marco de metaprogramación para eXist-db.
- Metaprogramación
- paradigmas de programación