Article de reference

Métaprogrammation

( Learn how and when to remove this message ) La métaprogrammation est une technique de programmation informatique permettant à un programme de traiter d'autres programmes comme...

(Learn how and when to remove this message)

La métaprogrammation est une technique de programmation informatique permettant à un programme de traiter d'autres programmes comme des données . Autrement dit, un programme peut être conçu pour lire, générer, analyser ou transformer d'autres programmes, voire se modifier lui-même, pendant son exécution. Dans certains cas, cela permet aux programmeurs de minimiser le nombre de lignes de code nécessaires pour exprimer une solution, réduisant ainsi le temps de développement. Elle offre également aux programmes une plus grande flexibilité pour gérer efficacement de nouvelles situations sans avoir à les recompiler.

La métaprogrammation permet de déplacer les calculs de l'exécution à la compilation , de générer du code à partir de calculs effectués à la compilation et de rendre possible l'automodification du code . La capacité d'un langage de programmation à être son propre métalangage permet la programmation réflexive , appelée réflexion . La réflexion est une fonctionnalité précieuse du langage qui facilite la métaprogrammation.

La métaprogrammation était populaire dans les années 1970 et 1980 grâce aux langages de traitement de listes comme Lisp . Le matériel informatique Lisp a connu un certain succès dans les années 1980 et a permis le développement d'applications capables de traiter du code. Ces machines étaient fréquemment utilisées pour des applications d'intelligence artificielle .

Approches

La métaprogrammation permet aux développeurs d'écrire des programmes et de créer du code relevant du paradigme de la programmation générique . Le fait que le langage de programmation lui-même soit un type de données de première classe (comme en Lisp , Prolog , SNOBOL ou Rebol ) est également très utile ; on parle alors d' homoiconicité . La programmation générique exploite les mécanismes de métaprogrammation au sein d'un langage, permettant ainsi d'écrire du code sans se soucier de la spécification des types de données, ceux-ci pouvant être fournis comme paramètres lors de leur utilisation.

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

  1. La première approche consiste à exposer les éléments internes du système d'exécution (moteur) au code de programmation via des interfaces de programmation d'applications (API) comme celle de l' émetteur .NET Common Intermediate Language (CIL).
  2. La seconde approche consiste en l'exécution dynamique d'expressions contenant des commandes de programmation, souvent composées de chaînes de caractères, mais pouvant également provenir d'autres méthodes utilisant des arguments ou le contexte, comme en JavaScript . Ainsi, « les programmes peuvent écrire des programmes ». Bien que les deux approches puissent être utilisées dans un même langage, la plupart des langages ont tendance à privilégier l'une ou l'autre.
  3. La troisième approche consiste à s'affranchir totalement du langage. Les systèmes de transformation de programmes à usage général, tels que les compilateurs , qui acceptent des 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 d'appliquer la métaprogrammation à pratiquement n'importe quel langage cible, indépendamment de ses propres capacités de métaprogrammation. On peut observer ce principe à l'œuvre avec Scheme , qui permet de surmonter certaines limitations du C en utilisant des constructions propres à Scheme pour étendre ce dernier.

Lisp est probablement le langage par excellence doté de fonctionnalités de métaprogrammation, tant de par son ancienneté historique que par la simplicité et la puissance de sa métaprogrammation. En Lisp, l'opérateur de déquotation (généralement une virgule) introduit du code évalué lors de la définition du programme plutôt qu'à l'exécution. Le langage de métaprogrammation est ainsi identique au langage hôte, et les routines Lisp existantes peuvent être directement réutilisées pour la métaprogrammation. Cette approche a été implémentée dans d'autres langages en intégrant un interpréteur au programme, qui manipule directement ses données. Il existe des implémentations de ce type pour certains langages de haut niveau courants, comme le script Pascal de RemObjects pour Object Pascal .

Utilisations

génération de code

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

#!/bin/sh # métaprogramme echo '#!/bin/sh' > programme for i in $( seq 992 ) do echo "echo $i " >> programme done chmod +x programme 

Ce script (ou programme) génère un nouveau programme de 993 lignes qui affiche les nombres de 1 à 992. Il s'agit d'un exemple d'utilisation du code pour en écrire davantage ; ce n'est pas la méthode la plus efficace pour afficher une liste de nombres. Néanmoins, un programmeur peut écrire et exécuter ce métaprogramme en moins d'une minute et générer ainsi plus de 1 000 lignes de code.

Une quine est un type particulier de métaprogramme qui génère son propre code source. Les quines présentent généralement un intérêt purement récréatif ou théorique.

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

Une approche générative consiste à utiliser des langages dédiés (DSL). Un exemple courant d'utilisation des DSL est la métaprogrammation générative : lex et yacc , deux outils permettant de générer des analyseurs lexicaux et syntaxiques , permettent à l'utilisateur de décrire le langage à l'aide d'expressions régulières et de grammaires hors contexte , et intègrent les algorithmes complexes nécessaires à une analyse syntaxique efficace.

Instrumentation du code

L'une des applications de la métaprogrammation est d'instrumenter les programmes afin de réaliser une analyse dynamique des programmes .

Défis

Certains affirment que la maîtrise des fonctionnalités de métaprogrammation exige un apprentissage approfondi. La métaprogrammation offrant une plus grande flexibilité et une meilleure configurabilité à l'exécution, son utilisation incorrecte ou inappropriée peut engendrer des erreurs inattendues et imprévues, extrêmement difficiles à déboguer pour un développeur moyen. Elle peut également introduire des risques et rendre le système plus vulnérable si elle n'est pas utilisée avec précaution. Parmi les problèmes courants liés à une mauvaise utilisation de la métaprogrammation, on peut citer l'incapacité du compilateur à identifier les paramètres de configuration manquants, ou encore des données invalides ou incorrectes pouvant provoquer des exceptions inconnues ou des résultats différents. C'est pourquoi certains estiment que seuls les développeurs hautement qualifiés devraient se consacrer au développement de fonctionnalités faisant appel à la métaprogrammation dans un langage ou une plateforme, et que les développeurs moyens doivent apprendre à utiliser ces fonctionnalités par convention.

Utilisations dans les langages de programmation

Systèmes macro

assembleurs macro

L' IBM/360 et ses dérivés disposaient de puissants outils d'assemblage de macros , souvent utilisés 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 transactionnel CICS comportaient des macros 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 :

Métaprogrammation de modèles

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 de pointe et rarement rencontrée en dehors des langages de programmation de recherche.

Mises en œuvre

La liste des systèmes de métaprogrammation notables est tenue à jour dans la liste des systèmes de transformation de programmes .