web-dev-qa-db-fra.com

Qu'est-ce que la métaprogrammation exactement?

Je lisais un article sur TheServerSide sur programmation ployglot sur la Java . Certains commentaires dans l'article se réfèrent à la métaprogrammation comme la capacité de générer du code (peut-être à la volée) ).

La métaprogrammation permet-elle de générer du code à la volée ou est-elle la capacité d'injecter des méthodes et des attributs dans des objets existants au moment de l'exécution (comme ce que certains langages dynamiques comme Python, Ruby et Groovy permettent).

107
Parag

La métaprogrammation fait référence à une variété de façons dont un programme se connaît ou peut se manipuler.

Dans des langages comme C #, la réflexion est une forme de métaprogrammation puisque le programme peut examiner des informations sur lui-même. Par exemple, renvoyer une liste de toutes les propriétés d'un objet.

Dans des langages comme ActionScript, vous pouvez évaluer des fonctions au moment de l'exécution pour créer de nouveaux programmes tels que eval ("x" + i). DoSomething () affecterait un objet appelé x1 lorsque i est 1 et x2 lorsque i est 2.

Enfin, une autre forme courante de métaprogrammation est lorsque le programme peut se changer de façon non triviale. LISP est bien connu pour cela et c'est quelque chose que Paul Graham a défendu il y a une dizaine d'années. Je vais devoir rechercher certains de ses essais spécifiques. Mais l'idée est que le programme changerait une autre partie du programme en fonction de son état. Cela permet un niveau de flexibilité pour prendre des décisions lors de l'exécution, ce qui est très difficile dans la plupart des langues populaires aujourd'hui.

Il convient également de noter qu'à l'époque de la programmation en assembleur simple, les programmes qui se modifiaient au moment de l'exécution étaient nécessaires et très courants.

Extrait de l'essai de Paul Graham "Ce qui rendait LISP différent" :

De nombreuses langues ont ce qu'on appelle une macro. Mais les macros LISP sont uniques. Et croyez-le ou non, ce qu'ils font est lié aux parenthèses. Les concepteurs de LISP n'ont pas mis toutes ces parenthèses dans le langage juste pour être différents. Pour le programmeur Blub, le code LISP semble bizarre. Mais ces parenthèses sont là pour une raison. Ils sont la preuve extérieure d'une différence fondamentale entre LISP et d'autres langues.

Le code LISP est constitué d'objets de données LISP. Et pas dans le sens trivial que les fichiers source contiennent des caractères, et les chaînes sont l'un des types de données pris en charge par la langue. Le code LISP, après avoir été lu par l'analyseur, est constitué de structures de données que vous pouvez parcourir.

Si vous comprenez comment fonctionnent les compilateurs, ce qui se passe réellement n'est pas tant que LISP a une syntaxe étrange que LISP n'a pas de syntaxe. Vous écrivez des programmes dans les arbres d'analyse qui sont générés dans le compilateur lorsque d'autres langues sont analysées. Mais ces arbres d'analyse sont entièrement accessibles à vos programmes. Vous pouvez écrire des programmes qui les manipulent. Dans LISP, ces programmes sont appelés macros. Ce sont des programmes qui écrivent des programmes.

Des programmes qui écrivent des programmes? Quand voudriez-vous faire ça? Pas très souvent, si vous pensez à Cobol. Tout le temps, si vous pensez en LISP. Ce serait pratique ici si je pouvais donner un exemple d'une macro puissante, et dire là-bas! et ça? Mais si je le faisais, cela ressemblerait à du charabia à quelqu'un qui ne connaissait pas LISP; il n'y a pas de place ici pour expliquer tout ce que vous devez savoir pour comprendre ce que cela signifie. En Ansi Common LISP J'ai essayé de faire avancer les choses aussi vite que possible, et même ainsi, je n'ai pas pu accéder aux macros jusqu'à la page 160.

Mais je pense que je peux donner une sorte d'argument qui pourrait être convaincant. Le code source de l'éditeur Viaweb était probablement composé d'environ 20-25% de macros. Les macros sont plus difficiles à écrire que les fonctions LISP ordinaires, et il est considéré comme un mauvais style de les utiliser lorsqu'elles ne sont pas nécessaires. Donc, chaque macro de ce code est là car elle doit l'être. Cela signifie qu'au moins 20 à 25% du code de ce programme fait des choses que vous ne pouvez pas facilement faire dans une autre langue. Aussi sceptique que le programmeur Blub puisse être sur mes prétentions pour les pouvoirs mystérieux de LISP, cela devrait le rendre curieux. Nous n'écrivions pas ce code pour notre propre plaisir. Nous étions une toute petite startup, programmant aussi dur que possible afin de mettre des barrières techniques entre nous et nos concurrents.

Une personne suspecte pourrait commencer à se demander s'il y avait une corrélation ici. Une grande partie de notre code faisait des choses qui sont très difficiles à faire dans d'autres langues. Le logiciel résultant a fait des choses que les logiciels de nos concurrents ne pouvaient pas faire. Peut-être qu'il y avait une sorte de connexion. Je vous encourage à suivre ce fil. Il y a peut-être plus que ce vieil homme qui boitille sur ses béquilles qu'il n'y paraît.

78
DavGarcia

Grande question. Je suis vraiment désolé de voir qu'aucune des réponses actuellement ne répond vraiment à votre question correctement. Je peux peut-être aider ...

La définition de la métaprogrammation est vraiment assez simple: cela signifie des programmes qui manipulent des programmes.

Votre réponse acceptée indique des programmes qui se manipulent eux-mêmes. Ce sont en effet des métaprogrammes mais ils sont un sous-ensemble de tous les métaprogrammes.

Tout:

  • Analyseurs
  • Langues spécifiques au domaine (DSL)
  • Langues spécifiques au domaine intégré (EDSL)
  • Compilateurs
  • Interprètes
  • Réécrivains de termes
  • Démonstrateurs de théorèmes

sont des métaprogrammes. Ainsi, le compilateur GCC est un métaprogramme, le interprète CPython est un métaprogramme, le système d'algèbre informatique Mathematica est un métaprogramme, le Prouveur de théorème Coq est un métaprogramme et ainsi de suite.

D'autres réponses ont affirmé que les métaprogrammes sont des programmes qui génèrent d'autres programmes. Ce sont effectivement des métaprogrammes mais, encore une fois, ils constituent un sous-ensemble de tous les métaprogrammes. La bibliothèque Transformation de Fourier la plus rapide de l'Ouest (FFTW) est un exemple d'un tel métaprogramme. Le code source est écrit principalement en OCaml et il génère des bits de code C (appelés codelets) qui sont combinés pour créer des routines hautes performances Fast Fourier Transform optimisées pour des machines spécifiques. Cette bibliothèque est en fait utilisée pour fournir les routines FFT dans Matlab. Les gens écrivent des programmes pour générer des méthodes numériques depuis des décennies, depuis les premiers jours de FORTRAN .

Le premier langage de programmation intégrant la prise en charge de la métaprogrammation était le langage LISt Processor (LISP) à la fin des années 1950. LISP 1.5 comprenait un certain nombre de fonctionnalités qui facilitaient la métaprogrammation. Premièrement, le type de données de base de LISP est des listes imbriquées, c'est-à-dire des arbres comme (a (b c) d), ce qui signifie que tout code LISP peut être exprimé nativement sous forme de structure de données. C'est ce qu'on appelle l'homoiconicité. Deuxièmement, le code LISP peut être facilement converti en données à l'aide de QUOTE. Par exemple (+ 1 2 3) ajoute 1 + 2 + 3 et (QUOTE (+ 1 2 3)) crée une expression qui ajoute 1 + 2 + 3 lorsqu'elle est évaluée. Troisièmement, LISP a fourni un évaluateur méta-circulaire qui vous permet d'utiliser l'interpréteur ou le compilateur Host pour évaluer le code LISP au moment de l'exécution, y compris le code LISP généré au moment de l'exécution. Les descendants de LISP incluent Scheme et Clojure . Dans toutes ces langues, la métaprogrammation est le plus souvent observée sous la forme de programmes qui se modifient, généralement à l'aide de macros.

Dans les années 1970, Robin Milner a développé un MetaLanguage (ML) qui a évolué vers la famille ML de langages de programmation qui comprend ML standard et OCaml et fortement influencé Haskell et F # . Ces langues facilitent l'expression d'autres langues. Dans ces langues, les métaprogrammes se présentent le plus souvent sous la forme de lexers, d'analyseurs, d'interprètes et de compilateurs.

En 1994, Erwin Unruh a découvert que le système de modèle C++ était Turing complet et pouvait être utilisé pour exécuter des programmes arbitraires au moment de la compilation . La métaprogrammation du modèle C++ a apporté la métaprogrammation aux masses non lavées qui (ab) l'ont utilisé pour de nombreuses choses, y compris la génération de méthodes numériques dans la bibliothèque Blitz ++ .

37
Jon Harrop

Eh bien, la métaprogrammation n'est que de la programmation, mais c'est essentiellement "écrire du code qui écrit du code" .

La capacité que vous mentionnez, lorsqu'un programme peut observer et modifier sa propre structure et son propre comportement est appelée réflexion et c'est un type de métaprogrammation.

Les langages typés dynamiquement ont de puissantes fonctionnalités de réflexion à l'exécution, rendues possibles par la nature interprétée de ces langages ...

Les langages typés statiques ont également de puissantes techniques de métaprogrammation, par exemple le C++ modèle de métaprogrammation ...

28
CMS

Ce n'est que mon opinion personnelle, qui est probablement la définition la plus libérale de la métaprogrammation.

Je pense que cela comprend:

  1. Compiler la génération de code ou la génération de code Runtime (ou les deux)
  2. Pensée orientée vers l'aspect ou programmation orientée vers l'aspect
  3. SEC Réflexion

Je pense que vous pouvez y arriver en utilisant n'importe lequel d'entre eux et en combinaison:

  1. Réflexion
  2. DSL (langages spécifiques au domaine)
  3. Attributs (.NET) ou annotations (Java)
  4. Génériques (.NET/Java)
  5. Modèles (C++)
  6. method_missing (Ruby)
  7. fermetures/fonctions de première classe/délégués
  8. AOP - Programmation orientée aspect
9
BuddyJoe

La métaprogrammation consiste à écrire un programme qui produit un autre programme. C'est quelque chose que les langages comme LISP sont vraiment bons. C'est beaucoup plus facile à faire dans un langage qui prend en charge de vraies macros (pas des macros C++, mais plutôt celles qui peuvent manipuler le code qu'elles produisent) comme Ruby, LISP, Scheme, etc. que dans un langage comme Java.

Une implémentation consiste à créer un "langage spécifique au domaine" qui est un moyen d'améliorer un langage de programmation pour accomplir une tâche spécifique. Il peut être incroyablement puissant s'il est fait correctement. Ruby on Rails est un bon exemple de ce type de programmation).

Si vous êtes intéressé à explorer cette méthode, consultez le Structure et interprétation des programmes informatiques qui est l'un des livres séminaux couvrant le sujet.

6
Steve Rowe

La métaprogrammation est l'écriture de programmes informatiques qui écrivent ou manipulent d'autres programmes (ou eux-mêmes) comme leurs données, ou qui effectuent une partie du travail à l'exécution qui serait autrement effectuée au moment de la compilation. Dans de nombreux cas, cela permet aux programmeurs de faire plus dans le même temps qu'ils prendraient pour écrire tout le code manuellement, ou cela donne aux programmes une plus grande flexibilité pour gérer efficacement de nouvelles situations sans recompilation. ( Source .)

Fondamentalement, c'est l'écriture de code qui génère plus de code, qui est exécuté pour atteindre un objectif. Cela se fait généralement dans la même langue (en utilisant javascript pour créer une chaîne javascript, puis eval it) ou pour émettre une autre langue (en utilisant .NET pour créer un fichier batch Windows).

4
EndangeredMassa

wikipedia a un bel article sur le sujet. Il n'est pas nécessaire de faire des modifications d'exécution pour que quelque chose soit qualifié de métaprogrammation. Par exemple, de nombreuses personnes utilisent des modèles C++ pour effectuer une métaprogrammation au moment de la compilation.

4
Mr Fooz