Métaprogrammation - Metaprogramming

La métaprogrammation est une technique de programmation dans laquelle les programmes informatiques ont la capacité de traiter d'autres programmes comme leurs données. Cela signifie qu'un programme peut être conçu pour lire, générer, analyser ou transformer d'autres programmes, et même se modifier en cours d'exécution. Dans certains cas, cela permet aux programmeurs de minimiser le nombre de lignes de code pour exprimer une solution, réduisant ainsi le temps de développement. Cela permet également aux programmes une plus grande flexibilité pour gérer efficacement de nouvelles situations sans recompilation.

La métaprogrammation peut être utilisée pour déplacer les calculs de l' exécution à la compilation , pour générer du code à l'aide des calculs au moment de la compilation et pour activer le code auto-modifiable . La capacité d'un langage de programmation à être son propre métalangage est appelée réflexion . La réflexion est une fonctionnalité précieuse du langage pour faciliter la métaprogrammation.

La métaprogrammation était populaire dans les années 1970 et 1980 en utilisant des langages de traitement de liste tels que LISP . Les machines matérielles LISP étaient populaires dans les années 1980 et permettaient des applications capables de traiter du code. Ils étaient fréquemment utilisés pour des applications d' intelligence artificielle .

Approches

La métaprogrammation permet aux développeurs d'écrire des programmes et de développer du code qui relève du paradigme de programmation générique . Avoir le langage de programmation lui-même comme type de données de première classe (comme dans Lisp , Prolog , SNOBOL ou Rebol ) est également très utile ; c'est ce qu'on appelle l' homoiconicité . La programmation générique invoque une fonction de métaprogrammation au sein d'un langage en permettant d'écrire du code sans se soucier de spécifier des types de données puisqu'ils peuvent être fournis en tant que paramètres lorsqu'ils sont utilisés.

La métaprogrammation fonctionne généralement de l'une des trois manières suivantes.

  1. La première approche consiste à exposer les composants internes du moteur d'exécution au code de programmation via des interfaces de programmation d'applications (API) comme celle de l' émetteur .NET IL .
  2. La deuxième approche est l'exécution dynamique d'expressions contenant des commandes de programmation, souvent composées de chaînes, mais pouvant également provenir d'autres méthodes utilisant des arguments ou un contexte, comme Javascript. Ainsi, "les programmes peuvent écrire des programmes". Bien que les deux approches puissent être utilisées dans la même langue, la plupart des langues ont tendance à pencher vers l'une ou l'autre.
  3. La troisième approche consiste à sortir complètement de la langue. Les systèmes de transformation de programmes à usage général tels que les compilateurs, qui acceptent les descriptions de langage et effectuent des transformations arbitraires sur ces langages, sont des implémentations directes de la métaprogrammation générale. Cela permet à la métaprogrammation d'être appliquée à pratiquement n'importe quel langage cible, sans se soucier du fait que ce langage cible possède ses propres capacités de métaprogrammation. On peut voir cela à l'œuvre avec Scheme et comment cela permet de s'attaquer à certaines limitations rencontrées en C en utilisant des constructions qui faisaient partie du langage Scheme lui-même pour étendre C.

Lisp est probablement le langage par excellence avec des facilités de métaprogrammation, à la fois en raison de sa préséance historique et en raison de la simplicité et de la puissance de sa métaprogrammation. Dans la métaprogrammation Lisp, l'opérateur unquote (généralement une virgule) introduit du code qui est évalué au moment de la définition du programme plutôt qu'au moment de l'exécution ; voir Formulaires d'auto-évaluation et citations en Lisp . Le langage de métaprogrammation est ainsi identique au langage de programmation hôte, et les routines Lisp existantes peuvent être directement réutilisées pour la métaprogrammation, si désiré. Cette approche a été mise en œuvre dans d'autres langues en incorporant un interpréteur dans le programme, qui travaille directement avec les données du programme. Il existe des implémentations de ce genre pour certaines langues de haut niveau commun, comme RemObjects de script Pascal pour Pascal Objet .

Coutumes

Génération de code

Un exemple simple de métaprogramme est ce script Shell POSIX , qui est un exemple de programmation générative :

#!/bin/sh
# metaprogram
echo '#!/bin/sh' > program
for i in $(seq 992)
do
    echo "echo $i" >> program
done
chmod +x program

Ce script (ou programme) génère un nouveau programme de 993 lignes qui imprime les nombres 1 à 992. Ceci n'est qu'une illustration de la façon d'utiliser du code pour écrire plus de code ; ce n'est pas le moyen le plus efficace d'imprimer une liste de nombres. Néanmoins, un programmeur peut écrire et exécuter ce métaprogramme en moins d'une minute, et aura généré plus de 1000 lignes de code dans ce laps de temps.

Un quine est un type spécial de métaprogramme qui produit son propre code source en sortie. Les quines n'ont généralement qu'un intérêt récréatif ou théorique.

Toutes les métaprogrammations n'impliquent pas une programmation générative. Si les programmes sont modifiables à l'exécution ou si la compilation incrémentielle est disponible (comme en C# , Forth , Frink , Groovy , JavaScript , Lisp , Elixir , Lua , Nim , Perl , PHP , Python , REBOL , Ruby , Rust , SAS , Smalltalk , et Tcl ), alors des techniques peuvent être utilisées pour effectuer une métaprogrammation sans générer réellement de code source.

Un style d'approche générative consiste à utiliser des langages spécifiques au domaine (DSL). Un exemple assez commun en utilisant DSLs implique metaprogramming générative: lex et yacc , deux outils utilisés pour générer des analyseurs lexicaux et parseurs , que l'utilisateur puisse décrire la langue en utilisant des expressions régulières et grammaires sans contexte , et intégrer les algorithmes complexes nécessaires pour analyser efficacement la Langue.

Instrumentation des codes

Une utilisation de la métaprogrammation est d'instrumenter des programmes afin d'effectuer une analyse dynamique de programme .

Changements de comportement

La métaprogrammation peut être utilisée pour tisser des changements de comportement dans un programme, comme dans la programmation orientée aspect . Par exemple, la métaprogrammation peut être utilisée pour injecter des indicateurs de fonctionnalité ou pour explorer des correctifs possibles pour corriger des bogues.

Défis

Certains soutiennent qu'il existe une courbe d'apprentissage rapide pour utiliser pleinement les fonctionnalités de métaprogrammation. Étant donné que la métaprogrammation offre plus de flexibilité et de configurabilité au moment de l'exécution, une mauvaise utilisation ou une utilisation incorrecte de la métaprogrammation peut entraîner des erreurs injustifiées et inattendues qui peuvent être extrêmement difficiles à déboguer pour un développeur moyen. Il peut introduire des risques dans le système et le rendre plus vulnérable s'il n'est pas utilisé avec précaution. Certains des problèmes courants qui peuvent survenir en raison d'une mauvaise utilisation de la métaprogrammation sont l'incapacité du compilateur à identifier les paramètres de configuration manquants, des données invalides ou incorrectes peuvent entraîner une exception inconnue ou des résultats différents. Pour cette raison, certains pensent que seuls les développeurs hautement qualifiés devraient travailler sur le développement de fonctionnalités qui exercent la métaprogrammation dans un langage ou une plate-forme et que les développeurs moyens doivent apprendre à utiliser ces fonctionnalités dans le cadre de la convention.

Utilisations dans les langages de programmation

Systèmes macro

Macro assembleurs

L' IBM/360 et ses dérivés disposaient de puissantes fonctions d' assemblage de macros qui étaient souvent utilisées pour générer des programmes complets en langage assembleur ou des sections de programmes (pour différents systèmes d'exploitation par exemple). Les macros fournies avec le système de traitement des transactions CICS avaient des macros d'assembleur qui généraient des instructions COBOL en tant qu'étape de pré-traitement.

D'autres assembleurs, tels que MASM , prennent également en charge les macros.

Métaclasses

Les métaclasses sont fournies par les langages de programmation suivants :

Modèle de métaprogrammation

Métaprogrammation par étapes

Types dépendants

L'utilisation de types dépendants permet de prouver que le code généré n'est jamais invalide. Cependant, cette approche est à la pointe de la technologie et se trouve rarement en dehors des langages de programmation de recherche.

Implémentations

La liste des systèmes de métaprogrammation notables est conservée dans Liste des systèmes de transformation de programme .

Voir également

Les références

Liens externes