J'ai entendu dans un certain nombre d'endroits maintenant que les gens s'attendent à ce que les langues utilisent, ou du moins aient, un compilateur auto-hébergé afin de mériter le respect.
Je suis curieux de savoir pourquoi c'est. Un compilateur semble être un logiciel très important à écrire, et j'imagine que toutes les langues ne sont pas bien adaptées à leur création. Ne serait-il pas plus judicieux de consacrer l'effort à travailler sur quelque chose qui donnera de meilleurs résultats?
Ne serait-il pas plus judicieux de consacrer l'effort à travailler sur quelque chose qui donnera de meilleurs résultats?
Comme ça?
Ce qui est bien avec les compilateurs, c'est qu'ils n'ont pas beaucoup de dépendances. Cela en fait de bons candidats pour une nouvelle langue qui n'a probablement pas encore de bibliothèque standard très large ou diversifiée.
Mieux encore, ils nécessitent une variété de choses, tout en étant bien étudiés. La variété permet de s'assurer que votre exemple teste différentes parties de la langue. Être bien étudié signifie que vous avez d'autres compilateurs à comparer - ainsi que donner plus de crédibilité aux types académiques que vous savez ce que vous faites.
Et bien que les compilateurs semblent une tonne de travail, ils sont assez petits dans le grand schéma des choses. Si les implémenteurs de langage ne peuvent même pas faire quelque chose qu'ils ont fait auparavant dans le nouveau langage, comment vont-ils faire des choses nouvelles? Comment vont-ils gérer les trucs vraiment gros comme les bibliothèques standard ou un IDE?
L'objectif d'avoir un compilateur dans le langage en cours de compilation fait souvent partie de la pratique de " manger votre propre nourriture pour chien ." Cela montre au monde que vous considérez que le langage, le compilateur et l'écosystème des modules et outils de support sont "assez bons pour un travail sérieux" ou "prêts pour la production".
Cela a également pour effet vertueux de forcer les personnes les plus proches du langage, du compilateur et de la conception d'exécution à faire face directement aux effets de toutes les décisions qu'ils ont prises et des priorités de développement qu'ils ont choisies - les verrues et tout. Cela conduit souvent à un groupe central qui non seulement comprend l'environnement linguistique en théorie, mais qui possède une vaste expérience pratique de l'utilisation du langage/des outils dans le creuset des conditions difficiles et réelles de Word.
Les gens créent de nouveaux langages à usage général pour une raison principale: ils détestent au moins une chose sur toutes les autres langues. C'est pourquoi tant de langues ne décollent pas. Vous avez une bonne idée d'un langage qui améliorerait votre vie de programmation, mais vous devez faire la première implémentation dans un langage qui vous agace d'au moins une façon. L'auto-hébergement signifie que vous n'avez plus à travailler dans cet ancien langage ennuyeux. C'est pourquoi les créateurs d'une langue travaillent vers cette étape et la voient comme une étape majeure.
Beaucoup de fonctionnalités linguistiques semblent bonnes sur papier, mais lorsque vous vous en servez pour les utiliser dans un vrai projet, vous commencez à voir leurs limites. Par exemple, de nombreuses langues ne disposent pas au départ d'un support décent Unicode. La réalisation d'un grand projet permet de garantir qu'un grand nombre de ces types de situations ont été rencontrées et traitées, et un compilateur auto-hébergé est aussi bon qu'un projet. C'est pourquoi les gens autres que les créateurs de la langue y voient une étape majeure.
Cela ne signifie pas que c'est le jalon seulement qui mérite d'être noté. Il existe des fonctionnalités qui ne sont pas exercées par un compilateur, telles que l'intégration de bases de données, les interfaces graphiques, la mise en réseau, etc.
Steve Yegge a écrit un excellent article de blog qui, quelque peu indirectement, résout ce problème.
Grand point n ° 1: les compilateurs englobent à peu près tous les aspects de l'informatique. Il s'agit d'un cours de niveau supérieur, car vous devez connaître toutes les autres choses que vous apprenez dans le programme d'informatique juste pour commencer. Structures de données, recherche et tri, performances asymptotiques, coloration graphique? Tout est là-dedans.
Il y a une raison pour laquelle Knuth travaille sur son monumental (et sans fin) "Art of Computer Programming" depuis plusieurs décennies, même s'il a commencé comme (juste) un manuel de compilation. De la même manière que Carl Sagan a dit "Si vous souhaitez faire un Apple tarte à partir de zéro, vous devez d'abord inventer l'univers", si vous souhaitez écrire un compilateur, vous devez d'abord traiter avec presque tous les aspects de l'informatique.
Cela signifie que si le compilateur est auto-hébergé, il est pratiquement sûr de pouvoir faire ce dont j'ai besoin, peu importe ce que je fais. Inversement, si vous ne l'avez pas fait écrivez un compilateur dans votre langage, il y a de fortes chances qu'il manque quelque chose de vraiment important pour quelqu'un, car les implémenteurs de langage n'ont jamais eu à écrire un programme qui en aurait besoin de penser à toutes ces questions.
Grand point # 2: à partir de 30 000 pieds, un nombre surprenant de problèmes ressemblent à des compilateurs.
Les compilateurs prennent un flux de symboles, déterminent leur structure selon certaines règles prédéfinies spécifiques au domaine et les transforment en un autre flux de symboles. Cela semble assez général, n'est-ce pas? Ben ouais.
Que vous soyez dans l'équipe Visual C++ ou non, vous aurez très souvent besoin de faire quelque chose qui ressemble à une partie d'un compilateur. Je le fais littéralement tous les jours.
Contrairement à la plupart des autres professions, les programmeurs n'utilisent pas seulement des outils, mais construisent leurs propres outils. Un programmeur qui ne peut pas (en raison du manque de compétences ou du manque d'outils utilisables pour construire d'autres outils) écrire des outils sera à jamais handicapé, limité aux outils que quelqu'un d'autre fournit.
Si un langage n'est "pas bien adapté à la création" de programmes qui peuvent prendre un flux de symboles, leur appliquer des règles et le transformer en un autre flux de symboles, cela ressemble à un langage assez limité, et pas un qui serait utile tome.
(Heureusement, je ne pense pas qu'il existe de nombreux langages de programmation qui ne conviennent pas à la transformation de symboles. C est probablement l'un des pires langages de ce type utilisé aujourd'hui, mais les compilateurs C sont généralement auto-hébergés, de sorte que personne n'a jamais été arrêté.)
Une troisième raison Je terminerai avec, par expérience personnelle, non mentionnée par Yegge (parce qu'il n'écrivait pas sur "pourquoi l'auto-hôte") : ça secoue les bugs. Lorsque vous écrivez un compilateur, cela signifie que chaque fois que vous compilez (pas seulement chaque fois que vous exécutez lui), vous dépendez de lui pour fonctionner, et pour fonctionner correctement sur une base de code de taille décente (le compilateur lui-même).
Ce mois-ci, j'utilise un compilateur non auto-hébergé relativement nouveau et célèbre (vous pouvez probablement deviner lequel), et je ne peux pas passer 2 jours sans commettre de faute. Je me demande combien les concepteurs ont réellement dû l'utiliser.
Si vous voulez qu'un compilateur pour la langue X soit auto-hébergé, vous devez d'abord l'implémenter dans une autre langue, disons Y, de sorte qu'il prenne des entrées pour la langue X et crache du code d'assemblage, ou du code intermédiaire, ou même code objet de la machine sur laquelle le compilateur s'exécute. Vous souhaitez que la langue Y soit aussi similaire que possible à la langue X, car à un moment donné, vous traduirez du code écrit en Y en X.
Mais vous ne voulez pas écrire plus de compilateur dans le langage Y que nécessaire, donc pour commencer, vous n'implémentez qu'un sous-ensemble du langage - éliminant les constructions redondantes. Dans le cas d'un langage de type 'C', tandis que mais pas pour ou faire pendant . si mais pas cas ou op. tertiaire Pas de structures, d'unions ou d'énumérations. Etc. Il vous reste juste assez de langue pour écrire un analyseur et un générateur de code rudimentaire pour la langue X. Ensuite, vérifiez la sortie. Encore.
Une fois que cela fonctionne, vous pouvez réécrire la source du compilateur qui a été écrite dans la langue Y dans la langue X et compiler la source de la langue X à l'aide du compilateur écrit dans la langue Y. La sortie sera un nouveau compilateur écrit dans la nouvelle langue X qui compile le langage X, c'est-à-dire qu'il est maintenant auto-hébergé. Cependant, il n'est pas complet car vous n'avez implémenté qu'un sous-ensemble de la langue dans la langue Y.
Alors maintenant, vous ajoutez les fonctionnalités manquantes, en testant chacune (ou un groupe de fonctionnalités) pour qu'elles génèrent du code correct. c'est-à-dire une fois que la fonctionnalité est implémentée dans le compilateur, vous pouvez écrire des programmes de test en utilisant les nouvelles fonctionnalités, les compiler et les tester, mais vous ne devriez pas encore les utiliser dans la source du compilateur. Une fois la ou les nouvelles fonctionnalités vérifiées, vous pouvez ensuite utiliser ces nouvelles fonctionnalités dans la source du compilateur elle-même - en remplaçant peut-être une partie du code d'origine écrit dans le sous-ensemble de langage - recompiler la source du compilateur en utilisant la version avec les nouvelles fonctionnalités.
Vous avez maintenant un mécanisme pour ajouter de nouvelles fonctionnalités au langage - et, une fois que la génération de code pour les fonctionnalités a été vérifiée correctement, elles peuvent être utilisées dans la prochaine génération du compilateur lui-même.
Il y a environ 60 ans, lorsque les ordinateurs sont arrivés sur la scène (et plus tard lorsque les microprocesseurs sont arrivés pour la première fois), il n'y avait pas d'autres langues Y adaptées pour implémenter le compilateur initial. Ainsi, les premiers compilateurs devaient être écrits en code Assembly, puis lorsque suffisamment de compilateur était en cours d'exécution, le code Assembly serait remplacé par la version écrite dans un nouveau langage. Pas d'assembleur non plus? L'ensemble du processeur a baissé d'un autre niveau, l'assembleur étant initialement écrit en code machine .
Est-il possible de produire un langage de programmation qui n'est pas bien conçu pour écrire un compilateur mais qui est bien conçu pour un autre but?
En regardant un langage comme SQL, je suppose que la réponse est oui. Mais les langues de cette nature ne sont pas d'usage général.
Qui dit ça? ... de toute façon, c'est juste une opinion. Certains pourraient être d'accord, d'autres non, il n'y a pas de bien ou de mal ici. Certaines langues ont des compilateurs écrits en eux-mêmes, d'autres non. Peu importe.
Néanmoins, je pense que c'est un bon exercice/preuve de concept si une langue est capable de "s'auto-compiler" ... c'est juste ... agréable ... et cela prouve que la langue est adaptée pour faire des choses complexes.
Je voudrais également mentionner que malgré sa gentillesse, il existe encore diverses raisons pour lesquelles un compilateur peut être écrit dans une autre langue. Par exemple, la plupart des moteurs javascript ne sont pas écrits en javascript. Il y a plusieurs raisons à cela: intégration avec d'autres logiciels, liaison à des bibliothèques/dépendances existantes, outils supérieurs, performances, code hérité ... Parfois, le langage auto-compilé est agréable, mais il est toujours logique de maintenir le compilateur de base dans un autre. Pourtant, le langage en lui-même a du sens. C'est juste que vous ne pouvez généralement pas vous permettre de réaménager un écosystème entier.
Clang est écrit en C++. Il ne serait pas trop difficile de réécrire le compilateur Clang Objective-C dans Objective-C, mais alors ce serait tout à fait inutile. Tout changement dans le compilateur C++ devrait être refait dans Objective-C et vice versa. Alors pourquoi?
Il y a maintenant un compilateur Clang Swift. Sûrement ce compilateur pourrait être réécrit dans Swift. Mais à quoi cela servirait-il? De démontrer que le langage est assez puissant pour y écrire un compilateur? Personne ne se soucie de savoir si vous pouvez écrire des compilateurs dans Swift. Les gens faire se soucient de savoir si vous pouvez écrire des interfaces utilisateur dans Swift, et vous le pouvez manifestement.
Si vous avez un compilateur bien testé qui peut facilement être adapté pour compiler différentes langues, il est tout à fait inutile de le réécrire dans différentes langues, à moins que la réécriture dans une langue différente ne facilite le travail avec le compilateur. Et s'il était logique d'écrire Clang dans Swift, par exemple, alors les compilateurs Clang C, C++ et Objective-C seraient tous écrits en Swift.
Il y a des choses plus importantes à faire que de prouver que vous pouvez écrire un compilateur dans un langage de programmation.
Cela montre que le langage est capable de traiter des chaînes complexes et de se traduire dans une autre langue/de s'interpréter lui-même.
Dans le processus de création d'un compilateur (le premier grand projet), il y aura un problème qui viendra au premier plan.