web-dev-qa-db-fra.com

Chaque langue peut-elle être classée comme compilée ou interprétée?

Selon Wikipedia: A langage compilé est un langage de programmation dont les implémentations sont généralement des compilateurs (traducteurs qui génèrent du code machine à partir du code source). Et un langage interprété est un type de langage de programmation pour lequel la plupart de ses implémentations exécutent des instructions directement et librement, sans avoir préalablement compilé un programme en instructions en langage machine.

Par conséquent, ce qui suit est clair.

  • C, C++ and few other similar languages - Langue compilée
  • Shell script, Perl, Ruby and some more - Langue interprétée

Cependant, il existe également un troisième type de langage. Des langages comme C # et Java qui utilisent à la fois un compilateur et un JIT lors de l'exécution. Ma question est donc, existe-t-il un nom distinct pour ces langages ou ils peuvent être classés dans l'un des types ci-dessus? Une réponse explicative serait plus utile?

MODIFIER:

D'après Wikipedia et ce SO post: interprété vs compilé il est évident qu'il existe 2 types d'implémentation de langage bien définis. Mais ma question porte sur le fait que c'est suffisant pour avoir 2 catégories, toutes les langues peuvent-elles entrer dans ces 2 ou y en a-t-il une 3ème?

14
Sisir

La réponse à votre question:

Chaque langue peut-elle être classée comme compilée ou interprétée?

Est "Non", mais pas pour la raison pour laquelle vous pensez que c'est le cas. La raison n'est pas qu'il existe une troisième catégorie manquante, la raison est que la catégorisation elle-même est absurde .

Il n'existe pas de "langage compilé" ou de "langage interprété". Ces termes ne sont même pas faux, ils sont absurdes.

Les langages de programmation sont des ensembles de règles mathématiques abstraites, de définitions et de restrictions. Les langages de programmation ne sont ni compilés ni interprétés. Les langages de programmation juste sont . [Le mérite revient à Shriram Krishnamurthi qui a dit cela dans une interview sur Channel il y a 9 ans (vers 51: 37-52: 20). ]

En fait, un langage de programmation peut parfaitement exister sans avoir aucun interprète ou compilateur! Par exemple, Konrad Zuse 's Plankalkül qu'il a conçu dans les années 1930 n'a jamais été mis en œuvre de son vivant. Vous pouvez toujours y écrire des programmes, vous pouvez analyser ces programmes, les raisonner, prouver leurs propriétés… vous ne pouvez tout simplement pas les exécuter. (Eh bien, en fait, même cela est faux: vous pouvez bien sûr les exécuter dans votre tête ou avec un stylo et du papier.)

La compilation et l'interprétation sont des traits du compilateur ou de l'interpréteur (duh!), Pas du langage de programmation. La compilation et l'interprétation vivent à un niveau d'abstraction différent des langages de programmation: un langage de programmation est un concept abstrait, une spécification, un morceau de papier. Un compilateur ou un interpréteur est un logiciel (ou matériel) concret qui implémente cette spécification. Si l'anglais était une langue dactylographiée, les termes "langue compilée" et "langue interprétée" seraient des erreurs de type. [Encore une fois, crédit à Shriram Krishnamurthi.]

Chaque langage de programmation peut être implémenté par un compilateur. Chaque langage de programmation peut être implémenté par un interprète. De nombreux langages de programmation grand public modernes ont à la fois interprété et compilé des implémentations. De nombreuses implémentations de langage de programmation hautes performances modernes ont à la fois des compilateurs et des interprètes.

Il existe des interprètes pour C et pour C++. D'un autre côté, chaque implémentation principale courante actuelle d'ECMAScript, PHP, Python, Ruby et Lua a un compilateur. La version originale du moteur ECMAScript V8 de Google était un pur compilateur de code machine natif. (Ils sont passés par plusieurs designs différents, et la version actuelle a un interprète, mais pendant de nombreuses années, il n'en a pas eu un.) XRuby et Ruby.NET était purement compilé Ruby implémentations. IronRuby a commencé comme une compilation purement Ruby implémentation, puis a ajouté un interpréteur plus tard afin d'améliorer les performances. - Opal est une implémentation Ruby purement compilée).

Certaines personnes pourraient dire que les termes "langage interprété" ou "langage compilé" ont un sens pour s'appliquer aux langages de programmation qui ne peuvent être implémentés que par un interprète ou par un compilateur. Mais, un tel langage de programmation n'existe pas. Chaque langage de programmation peut être implémenté par un interprète et par un compilateur.

Par exemple, vous pouvez dériver automatiquement et mécaniquement un compilateur d'un interprète à l'aide de la seconde projection Futamura. Il a été décrit pour la première fois par Prof. Yoshihiko Futamura dans son article de 1971 Évaluation partielle du processus de calcul - Une approche d'un compilateur-compilateur (japonais) , un version anglaise qui a été republié 28 ans plus tard. Il utilise évaluation partielle , en évaluant partiellement l'évaluateur partiel lui-même par rapport à l'interpréteur, ce qui donne un compilateur.

Mais même sans de telles transformations hautement académiques complexes, vous pouvez créer quelque chose qui est fonctionnellement impossible à distinguer de la compilation d'une manière beaucoup plus simple: il suffit de regrouper l'interpréteur avec le programme à interpréter en un seul exécutable.

Une autre possibilité est l'idée d'un "méta-JIT". (Ceci est lié dans l'esprit aux projections Futamura.) C'est par exemple utilisé dans le framework RPython pour implémenter des langages de programmation. Dans RPython, vous écrivez un interpréteur pour votre langue, puis le framework RPython compilera JIT votre interprète pendant qu'il interprète le programme, produisant ainsi une version compilée spécialisée de l'interpréteur qui ne peut interpréter que ce seul programme - qui est à nouveau indiscernable de la compilation de ce programme. Donc, dans un certain sens, RPython génère dynamiquement des compilateurs JIT à partir d'interprètes.

Dans l'autre sens, vous pouvez envelopper un compilateur dans un wrapper qui compile d'abord le programme, puis l'exécute directement, ce qui rend ce compilateur encapsulé impossible à distinguer d'un interpréteur. C'est en fait ainsi que le Scala REPL, le C♯ REPL (à la fois en Mono et .NET), le Clojure REPL, le GHC REPL interactif) et de nombreux autres REPL sont implémentés. Ils prennent simplement une ligne/une instruction/une expression, le compilent, l'exécutent immédiatement et affichent le résultat. Ce mode d'interaction avec le compilateur est donc indiscernable d'un interprète, que certaines personnes utilisent réellement l'existence d'un REPL pour le langage de programmation comme caractéristique définissant ce que signifie être un "interprété") langage de programmation".

Notez cependant que vous ne pouvez pas exécuter un programme sans interprète. Un compilateur traduit simplement un programme d'une langue à une autre. Mais c'est tout. Vous avez maintenant le même programme, juste dans une langue différente. La seule façon d'obtenir réellement un résultat du programme est d'interpréter il. Parfois, le langage est un langage machine binaire extrêmement simple, et l'interpréteur est en fait codé en dur en silicone (et nous l'appelons un "CPU"), mais c'est toujours une interprétation.

Certaines personnes disent que vous pouvez appeler un langage de programmation "interprété" si la majorité de ses implémentations sont des interprètes. Eh bien, regardons un langage de programmation très populaire: ECMAScript. Il existe un certain nombre d'implémentations grand public très performantes et prêtes pour la production d'ECMAScript, et chacune d'entre elles comprend au moins un compilateur , certains compilateurs même multiples. Ainsi, selon cette définition, ECMAScript est clairement un langage compilé.

Vous pourriez également être intéressé par ma réponse, qui explique les différences et les différents moyens de combiner les interprètes, les compilateurs JIT et les compilateurs AOT et cette réponse traitant des différences entre un compilateur AOT et un compilateur JIT .

Il est possible de catégoriser les implémentations du langage dans une certaine mesure. En général, nous avons la distinction entre

  • compilateurs et
  • interprètes (si l'interprète interprète un langage qui n'est pas destiné aux humains, il est aussi souvent appelé une machine virtuelle )

Dans le groupe de compilateurs, nous avons la distinction temporelle lorsque le compilateur est exécuté:

  • Les compilateurs Just-In-Time exécutent pendant que le programme s'exécute
  • Les compilateurs anticipés exécutent avant le programme démarre

Et puis nous avons des implémentations qui combinent interprètes et compilateurs, ou combinent plusieurs compilateurs, ou (beaucoup plus rare) plusieurs interprètes. Certaines combinaisons typiques sont

  • moteurs d'exécution en mode mixte qui combinent un interpréteur et un compilateur JIT qui traitent tous les deux le même programme en même temps (exemples: Oracle HotSpot JVM, IBM J9 JVM)
  • multi-phase [J'ai inventé ce terme; Je ne connais pas de moteur d'exécution largement utilisé], où la première phase est un compilateur qui compile le programme dans un langage plus approprié pour la phase suivante, puis une deuxième phase qui traite ce langage. (Il peut y avoir plus de phases, mais deux sont typiques.) Comme vous pouvez probablement le deviner, la deuxième phase peut à nouveau utiliser différentes stratégies de mise en œuvre:
    • un interprète: c'est une stratégie de mise en œuvre typique. Souvent, le langage qui est interprété est une forme de bytecode optimisé pour l '"interprétabilité". Exemples: CPython, YARV (pré-2.6) , Zend Engine
    • un compilateur, ce qui en fait une combinaison de deux compilateurs. En règle générale, le premier compilateur traduit le langage en une certaine forme de bytecode optimisé pour la "compilabilité" et le deuxième compilateur est un compilateur d'optimisation spécifique à la plate-forme cible
    • une machine virtuelle en mode mixte. Exemples: YARV post-2.6, Rubinius, SpiderMonkey, SquirrelFish Extreme, Chakra

Mais il y en a encore d'autres. Certaines implémentations utilisent deux compilateurs au lieu d'un compilateur et d'un interprète pour obtenir les mêmes avantages qu'un moteur en mode mixte (par exemple, les premières années, la V8 a fonctionné de cette façon).

RPython combine un interpréteur de bytecode et un JIT, mais le JIT ne compile pas le programme utilisateur, il compile l'interpréteur de bytecode pendant qu'il interprète le programme utilisateur! La raison en est que RPython est un framework pour implémenter les langages, et de cette manière, un implémenteur de langage n'a qu'à écrire l'interpréteur de bytecode et obtient un JIT gratuitement. (L'utilisateur le plus connu de RPython est bien sûr PyPy .)

Le Truffle framework interprète un AST indépendant du langage, mais en même temps il se spécialise lui-même pour l'AST spécifique, qui est sorte de compilation comme mais pas non plus. Le résultat final est que Truffle peut exécuter le code extrêmement rapidement, sans en savoir trop sur les spécificités du langage. (Truffle est également un cadre générique pour les implémentations de langage.) Parce que le AST est indépendant de la langue, vous pouvez mélanger et faire correspondre plusieurs langues dans le même programme, et Truffle est capable d'effectuer des optimisations entre les langues , comme l'inclusion d'une méthode Ruby dans une fonction ECMAScript, etc.

Les macros et eval sont parfois citées comme des fonctionnalités qui ne peut pas être compilé. Mais c'est faux. Il existe deux façons simples de compiler des macros et eval. (Notez que pour les besoins de la compilation, les macros et eval sont quelque peu duales les unes aux autres et peuvent être gérées en utilisant des moyens similaires.)

  1. Utilisation d'un interpréteur: pour les macros, vous intégrez un interpréteur dans le compilateur. Pour eval, vous intégrez un interpréteur dans le programme compilé ou dans les bibliothèques de support d'exécution.
  2. Utilisation d'un compilateur: pour les macros, vous compilez d'abord la macro, puis incorporez la macro compilée dans votre compilateur et compilez le programme à l'aide de ce compilateur "étendu". Pour eval, vous intégrez un compilateur dans le programme compilé ou dans les bibliothèques de support d'exécution.
48
Jörg W Mittag

Si nous sommes pédant, il n'y a pas de langage compilé ou interprété, car n'importe quel langage pourrait en principe être implémenté par un compilateur ou un interprète. Cependant, la plupart des langues suivent une stratégie de mise en œuvre relativement cohérente. C++ est presque toujours compilé en code natif. Python est presque toujours exécuté via un interpréteur de bytecode. Java est presque toujours exécuté via un comiler JIT. Donc, si nous n'insistons pas sur un pédantisme obtus) , il est logique de parler de langages compilés ou interprétés.

Cependant, la stratégie d'implémentation du langage ne correspond pas parfaitement à la dichotomie compilée/interprétée. Essentiellement, aucune langue n'est strictement interprétée, exécutée directement à partir de la source. Ce serait très lent. Au lieu de cela, pratiquement toutes les implémentations de langage "interprétées" compilent la source en quelque chose (souvent du bytecode) qui peut être exécuté de manière plus efficace. En plus de cela, certaines implémentations JIT compilent ce bytecode en code natif au moment de l'exécution. Même les langues que nous considérons comme étant compilées contiennent souvent une certaine quantité d'interprétation. Par exemple, printf en C est effectivement un interpréteur de la chaîne de format.

Donc, je dirais qu'il n'est pas logique d'essayer de catégoriser les langues en compilées ou interprétées. Presque toutes les langues sont un certain degré d'hybride entre les deux approches. (Et oui, si nous sommes pédant, ce sont les implémentations de langage et non les langages qui sont compilés/interprétés).

13
Winston Ewert

Non, la classification compilée vs interprétée n'est pas pertinente pour les langues.

Les compilateurs et les interprètes ne sont que des moyens de livrer une langue. Et la technologie derrière ces moyens évolue. Exemples pratiques:

  • À la fin des années 80 Instant C de Rational Systems était un interpréteur C (oui! ). C'était assez impressionnant bien que trop lent pour un développement sensible aux performances.
  • Pendant longtemps, BASIC était un langage typiquement interprété. Mais tout d'un coup, un marché de compilateurs BASIC est apparu (par exemple Visual Basic).
  • CSD Pascal , le premier langage livré avec une machine virtuelle était considéré par beaucoup comme un compilateur, car le code source était compilé en un bytecode, le p-code. Mais certains l'ont vu dans la catégorie des interprètes car le p-code n'était en réalité pas compilé en code machine mais lui-même interprété, avec pour conséquence une performance plus lente.
  • Transpilers étaient et sont encore utilisés pour convertir une langue en une autre, éventuellement en une langue compilée, en utilisant des bibliothèques supplémentaires pour faire face aux constructions de langage plus dynamiques.
  • La machine virtuelle combinée avec technologie de compilateur JIT (par exemple JVM, CLI/CLR) permet aujourd'hui de compiler beaucoup de langage initialement interprété (exemples: IronPython pour Ptyhton, ou - Clojure comme dialecte LISP).

Enfin un article intéressant de la façon dont le même langage peut évoluer d'interprété à compilé.

1
Christophe

Certaines versions de Basic symbolisent les instructions dans un fichier de code source, quelque chose entre interprétatif et compilé.

APL (un langage de programmation), a un opérateur d'exécution, qui prend une chaîne variable comme paramètre, puis l'interprète et l'exécute. Il existe un opérateur de création de fonction, qui prend une matrice de chaînes variables et crée une fonction à partir de celle-ci. Cela nécessiterait un certain type de compilation au moment de l'exécution afin de considérer le langage comme compilé.

0
rcgldr

Sous la définition OP de langage compilé et langage interprété .

Les autres catégories seraient:

  • Aucun. Une langue pour laquelle il n'existe ni interprètes ni compilateurs. C'est le cas de nombreux langages en informatique académique.
  • Mixte. Un langage pour lequel la plupart de ses implémentations le compilent et l'exécutent partiellement. Comme OP le mentionne, c'est le cas pour Java. Et non, je ne connais pas de nom populaire pour cette catégorie. Les langues compilées JIT sont ce à quoi je les entends le plus souvent.

Une langue peut changer de catégorie à mesure que de nouveaux outils sont développés ou que les tendances d'utilisation changent.

0
Anonymous Coward