it-swarm-fr.com

Pourquoi les macros ne sont-elles pas incluses dans la plupart des langages de programmation modernes?

Je sais qu'ils sont mis en œuvre extrêmement parfumé à C/C++. Ne peuvent-ils pas être mis en œuvre de manière plus sûre? Les inconvénients des macros sont-ils vraiment assez graves pour l'emporter sur le pouvoir massif qu'ils fournissent?

33
Casebash

Je pense que la raison principale est que les macros sont lexical. Cela a plusieurs conséquences:

  • Le compilateur n'a aucun moyen de vérifier qu'une macro est sémantiquement fermée, c'est-à-dire qu'elle représente une "unité de sens" comme une fonction. (Considérons #define TWO 1+1 - Que fait TWO*TWO Égal? 3.)

  • Les macros ne sont pas typées comme des fonctions sont. Le compilateur ne peut pas vérifier que les paramètres et le type de retour ont un sens. Il ne peut que vérifier l'expression expansée qui utilise la macro.

  • Si le code ne compile pas, le compilateur n'a aucun moyen de savoir si l'erreur est dans la macro elle-même ou l'endroit où la macro est utilisée. Le compilateur signalera le mauvais endroit la moitié de l'époque, soit il doit signaler à la fois que l'un d'entre eux est probablement bien. (Considérons #define min(x,y) (((x)<(y))?(x):(y)): Que doit faire le compilateur si les types de x et y ne correspondent pas ou ne mettez pas en œuvre operator<?)

  • Les outils automatisés ne peuvent pas travailler avec eux de manière sémantine utile. En particulier, vous ne pouvez pas avoir des choses comme Intellisense pour les macros qui fonctionnent comme des fonctions, mais développent une expression. (Encore une fois, l'exemple min.)

  • Les effets secondaires d'une macro ne sont pas aussi explicites qu'avec des fonctions, provoquant une confusion potentielle pour le programmeur. (Considérez à nouveau l'exemple min _ Exemple: dans un appel de la fonction, vous savez que l'expression pour x est évaluée une seule fois, mais ici, vous ne pouvez pas savoir sans regarder la macro.)

Comme je l'ai dit, ce sont toutes des conséquences du fait que les macros sont lexicales. Lorsque vous essayez de les transformer en quelque chose de plus approprié, vous vous retrouvez avec des fonctions et des constantes.

58
Timwi

Mais oui, macros peut être conçu et mis en œuvre mieux qu'en C/C++.

Le problème avec les macros est qu'ils sont efficacement a Extension de syntaxe de langue Mécanisme qui réécrit votre code dans quelque chose d'autre.

  • Dans le cas C/C++, il n'y a pas de vérification fondamentale de la santé mentale. Si vous faites attention, les choses vont bien. Si vous faites une erreur ou si vous utilisez des macros, vous pouvez avoir de gros problèmes.

    Ajoutez à cela que de nombreuses choses simples que vous puissiez faire avec (C/C++ Style) Les macros peuvent être effectuées d'une autre manière dans d'autres langues.

  • Dans d'autres langues telles que divers dialectes LISP, les macros sont mieux intégrées à la syntaxe des langues principales, mais vous pouvez toujours avoir des problèmes avec des déclarations dans une "fuite" macro. Ceci est abordé par macros hygiéniques .


Bref contexte historique

Les macros (courts pour la macro-instructions) sont apparus pour la première fois dans le contexte de la langue d'assemblage. Selon - Wikipedia , des macros étaient disponibles dans certains assembleurs IBM dans les années 1950.

Le LISP original n'avait pas de macros, mais ils ont été introduits pour la première fois à MacLisp au milieu des années 1960: https://stackoverflow.com/questions/3065606/when-de-the-idea-of-macros-utilisateur -Défini-transformation-transformation-apparaître . http://www.csee.umbc.edu/courses/331/resources/papers/evolution-of-lisp.pdf . Avant cela, "FEXPRS" a fourni des fonctionnalités de type macro.

Les premières versions de C n'ont pas eu de macros ( http://cm.bell-labs.com/cm/cs/who/dmr/chist.html ). Celles-ci ont été ajoutées CIRCA 1972-73 via un préprocesseur. Avant cela, c Seulement pris en charge #include et #define.

Le macro-préprocesseur M4 est originaire de CIRCA 1977.

Des langues plus récentes implémentent apparemment des macros où le modèle de fonctionnement est syntaxique plutôt que textuel.

Alors, quand quelqu'un parle de primacy d'une définition particulière du terme "macro", il est important de noter que la signification a évolué au fil du temps.

13
Stephen C

Les macros peuvent, comme notes Scott , vous permettent de masquer la logique. Bien sûr, les fonctions, les classes, les bibliothèques et de nombreux autres dispositifs communs sont donc.

Mais un puissant système de macro peut aller plus loin, vous permettant de concevoir et d'utiliser la syntaxe et les structures qui ne sont pas normalement trouvées dans la langue. Cela peut être un outil merveilleux: des langues spécifiques à un domaine, des générateurs de code et plus encore dans le confort d'un environnement de langue unique ...

Cependant, il peut être maltraité. Il peut rendre le code plus difficile à lire, à comprendre et à déboguer, augmenter le temps nécessaire aux nouveaux programmeurs de se familiariser avec une base de codes et entraîner des erreurs et des retards coûteux.

Donc, pour les langues destinées à simplifier Programmation (comme Java ou python), un tel système est un anathème.

12
Shog9

Les macros peuvent être mises en œuvre très en toute sécurité dans certaines circonstances - dans Lisp par exemple, les macros ne sont que des fonctions qui renvoient du code transformé en tant que structure de données (expression S). Bien entendu, LISP bénéficie de manière significative du fait que c'est homoiconique et le fait que "le code est des données".

Cet exemple de clojure peut être un exemple de la facilité d'utilisation des macros qui spécifie une valeur par défaut à utiliser en cas d'exception:

(defmacro on-error [default-value code]
  `(try ~code (catch Exception ~'e ~default-value)))

(on-error 0 (+ nil nil))               ;; would normally throw NullPointerException
=> 0                                   ;l; but we get the default value

Même à Lisps cependant, l'avis général est "N'utilisez pas de macros à moins que vous ne l'iez".

Si vous n'utilisez pas une langue homoicoiconique, les macros deviennent beaucoup plus difficiles et les différentes autres options ont tous des pièges:

  • Macros - E.G. Le préprocesseur C - simple à mettre en œuvre mais très délicat à utiliser correctement, car vous devez générer la syntaxe de source correcte sous forme textuelle, y compris les bizutechniques syntaxiques
  • DSL à base de macro - E.G. le système de modèle C++. Complexe, peut lui-même entraîner une syntaxe délicate, peut être extrêmement complexe pour les écrivains du compilateur et des outils à manipuler correctement car il introduit une nouvelle complexité importante dans la syntaxe et la sémantique de la langue.
  • API de manipulation ast/bytecode - E.G. Java Réflexion/Bytecode Generation - théoriquement très flexible mais peut devenir très verbeuse: il peut nécessiter beaucoup de code pour faire des choses assez simples. Si cela prend dix lignes de code pour générer l'équivalent d'une Fonction à trois lignes, alors vous n'avez pas beaucoup gagné avec vos efforts de méta-programmation ...

De plus, tout ce qu'une macro peut faire peut finalement être atteint d'une autre manière dans une langue complète de Turing (même si cela signifie écrire beaucoup de plaque chauffante). À la suite de toutes ces difficultés, il n'est pas surprenant que de nombreuses langues décident que les macros ne valent pas vraiment le tout pour mettre en œuvre.

6
mikera

Pour répondre à vos questions, pensez à quelles macros sont principalement utilisées pour (avertissement: code compilé du cerveau).

  • Macros utilisées pour définir des constantes symboliques #define X 100

Cela peut facilement être remplacé par: const int X = 100;

  • Macros utilisées pour définir (essentiellement) fonctions de type-agnostique en ligne #define max(X,Y) (X>Y?X:Y)

Dans n'importe quelle langue prenant en charge la surcharge de fonction, cela peut être émulé de manière beaucoup plus sûre en ayant des fonctions surchargées du type correct, ou dans une langue prenant en charge les génériques, par une fonction générique. La macro tente judicieuse tenter de comparer n'importe quoi, y compris des pointeurs ou des cordes, ce qui pourrait compiler, mais n'est certainement pas ce que vous vouliez. D'autre part, si vous avez fabriqué des macros de type sécurisé, ils n'offrent aucun avantage ni de commodité sur les fonctions surchargées.

  • Les macros utilisées pour spécifier des raccourcis sur des éléments souvent utilisés. #define p printf

Ceci est facilement remplacé par une fonction p() qui fait la même chose. Ceci est tout à fait impliqué dans C (vous oblige à utiliser la famille va_arg() Famille de fonctions) mais dans de nombreuses autres langues prenant en charge le nombre variable d'arguments de fonction, il est beaucoup plus simple.

Soutenir ces fonctionnalités dans Une langue plutôt que dans une langue macro spéciale est plus simple, moins d'erreur sujette et beaucoup moins déroutante pour les autres lisant le code. En fait, je ne peux pas penser à un cas Single utilisation pour les macros qui ne peuvent facilement être dupliqués d'une autre manière. Le seulement Place où les macros sont vraiment utiles sont quand ils sont liés à des constructions de compilation conditionnelle telles que #if (Etc.).

Sur ce point, je ne discuterai pas avec vous, puisque je crois que les solutions de non-préprocesseur à la compilation conditionnelle dans les langues populaires sont extrêmement lourdes (comme l'injection de bytecode en Java). Mais des langues comme d ont été proposées avec des solutions qui ne nécessitent pas de préprocesseur et ne sont pas plus lourdes que d'utiliser des conditionnels de préprocesseur, tout en étant beaucoup moins sujet aux erreurs.

5
Chinmay Kanchi

Les monnaies de la part en notant que les macros en C/C++ sont très limitées, sont sujettes aux erreurs et non vraiment utiles.

Les macros comme implémentées dans Say Lisp, ou Z/OS Assembleur peuvent être fiables et incroyablement utiles.

Mais à cause de l'abus de la fonctionnalité limitée en C, ils ont rassemblé une mauvaise réputation. Donc, personne ne met plus en œuvre les macros, au lieu de cela, vous obtenez des choses comme des modèles qui font certaines des macros simples de choses utilisées pour faire et des choses comme les annotations de Java qui font certaines des macro de la macro plus complexes.

2
James Anderson

Le plus gros problème que j'ai vu avec des macros est que, lorsque fortement utilisé, ils peuvent rendre le code très difficile à lire et à entretenir car ils vous permettent de masquer la logique dans la macro qui peut ou non être facile à trouver (et peut ne pas être triviale. ).

2
Scott Dorman