Pourquoi les bibliothèques standard ne sont-elles pas des primitives de langage de programmation? [fermé]

30

Je pensais pourquoi existe-t-il (dans tous les langages de programmation que j'ai appris, comme C ++, Java, Python) des bibliothèques standard comme stdlib, au lieu d'avoir des "fonctions" similaires étant une primitive du langage lui-même.

Simone Broili
la source
4
Que voulez-vous dire par "pourquoi le compilateur ne pourrait-il pas simplement traduire un appel de fonction en un ensemble d'instructions"? C'est à peu près ce que fait le compilateur, bibliothèque standard ou non (Ok, Python uniquement à mi-chemin et bytecode Java vers JVM; concept similaire). Les bibliothèques standard n'ont vraiment rien à voir avec la compilation de code -> instructions.
Delioth
25
@Delioth Je pense que Simone se demande pourquoi tout dans la bibliothèque standard de langage $ LANG n'est pas une construction / fonction primitive de ce langage à la place. Je dirais que c'est une question raisonnable pour quiconque est très nouveau dans les langages de programmation :)
Andres F.
33
La bibliothèque standard comble généralement l'écart entre un langage de programmation fonctionnel et un langage utile que les gens utiliseront.
Telastyn
6
Une partie importante de la bibliothèque standard de Python est en fait écrite en C et déjà compilée.
ElmoVanKielmo
1
En revanche, dans la plupart des implémentations de BASIC, tout fait partie du langage et il n'y a pas de bibliothèques du tout ni de support pour elles (sauf, dans plusieurs implémentations, pour la possibilité d'appeler des routines en langage machine).
Euro Micelli

Réponses:

32

Permettez-moi de développer un peu la bonne réponse de @ Vincent (+1) :

Pourquoi le compilateur ne pouvait-il pas simplement traduire un appel de fonction en un ensemble d'instructions?

Il peut et le fait via au moins deux mécanismes:

  • en insérant un appel de fonction - pendant la traduction, le compilateur peut remplacer un appel de code source avec son implémentation directement en ligne au lieu de faire un appel réel à la fonction. La fonction doit toujours avoir une implémentation définie quelque part et qui peut être dans la bibliothèque standard.

  • fonction intrinsèque - les fonctions intrinsèques sont des fonctions dont le compilateur a été informé sans nécessairement trouver la fonction dans une bibliothèque. Celles-ci sont généralement réservées aux fonctionnalités matérielles qui ne sont pratiquement accessibles d'aucune autre manière, étant si simples que même la surcharge d'une fonction de bibliothèque de langage d'assemblage est considérée comme élevée. (Le compilateur ne peut généralement incorporer automatiquement que du code source dans son langage, mais pas les fonctions d'assemblage, c'est là qu'intervient le mécanisme intrinsèque.)

Cela étant dit, la meilleure option consiste parfois pour le compilateur à traduire un appel de fonction dans le langage source en un appel de fonction dans le code machine. La récursivité, les méthodes virtuelles et la taille pure sont quelques raisons pour lesquelles l'inline n'est pas toujours possible / pratique. (Une autre raison est l'intention de la construction, comme la compilation séparée (modules d'objet), les unités de charge distinctes (par exemple les DLL)).

Il n'y a pas non plus d'avantage réel à rendre intrisiques la plupart des fonctions de bibliothèque standard (cela coderait en dur beaucoup plus de connaissances dans le compilateur pour aucun avantage réel), donc un appel de code machine à nouveau est souvent le plus approprié.

C est un langage notable qui a sans doute omis d'autres déclarations de langage explicites en faveur des fonctions de bibliothèque standard. Bien que les bibliothèques préexistaient, ce langage a changé pour faire plus de travail à partir des fonctions de bibliothèque standard et moins comme des déclarations explicites dans la grammaire du langage. IO dans d'autres langages, par exemple, a souvent reçu sa propre syntaxe sous la forme de diverses instructions, tandis que la grammaire C ne définit aucune instruction IO, se contentant plutôt de se reporter à sa bibliothèque standard pour le fournir, accessible via des appels de fonction, qui le compilateur sait déjà comment faire.

Erik Eidt
la source
3
Bonne réponse. Il faut ajouter quelques mots pour expliquer pourquoi cette décision en C a été prise: si je me souviens bien, la principale raison était en fait parce qu'elle facilitait la création de compilateurs C pour de nombreuses architectures matérielles différentes.
Doc Brown
10
@DocBrown En 1975, il y avait suffisamment d'exemples dans le domaine du développement du langage de programmation (ALGOL-68, n'importe qui?) Qui montraient que les tentatives de tout intégrer dans le langage conduisaient directement à des ralentissements considérables dans la définition des spécifications du langage et dans la production d'implémentations de langage.
Joker_vD
5
Un exemple similaire est ce que Python a fait avec print: dans 2.x, c'était une instruction , avec sa propre grammaire spéciale, mais dans 3.x, c'est devenu juste un autre appel de fonction. Voir PEP 3105 pour l'explication officielle.
dan04
1
@DocBrown, la portabilité n'était certainement pas une raison. Lorsque Unix et C ont été créés, ils ont été conçus et construits pour exactement une machine, un PDP-7 de rechange, alors que Ken Thompson se demandait quels concepts pouvaient être récupérés du projet Multics échoué. C a également été créé pour une raison: avoir un langage de haut niveau dans lequel (re) implémenter Unix. Ils sont fondamentalement une expérience dans la conception de logiciels, pas une tentative sérieuse d'OS et de langage multi-plateformes commerciaux. Voir bell-labs.com/usr/dmr/www/chist.html par exemple.
Euro Micelli
@EuroMicelli: Je ne vois pas de contradiction. Et votre référence contient beaucoup de détails sur le moment où la portabilité est devenue importante, c'était en fait dans les premières années du développement C et Unix. Je ne peux que deviner ici, mais si les inventeurs C n'avaient pas gardé le langage intentionnellement petit, je pense qu'il aurait été très peu probable qu'ils l'aient porté aussi rapidement et avec succès vers de nombreuses architectures différentes.
Doc Brown
70

Il s'agit simplement de garder la langue elle-même aussi simple que possible. Vous devez faire la distinction entre une caractéristique du langage, comme un type de boucle ou des façons de transmettre des paramètres aux fonctions, etc., et les fonctionnalités courantes dont la plupart des applications ont besoin.

Les bibliothèques sont des fonctions qui peuvent être utiles à de nombreux programmeurs, elles sont donc créées sous forme de code réutilisable qui peut être partagé. Les bibliothèques standard sont conçues pour être des fonctions très courantes dont les programmeurs ont généralement besoin. De cette façon, le langage de programmation est immédiatement utile à un plus large éventail de programmeurs. Les bibliothèques peuvent être mises à jour et étendues sans modifier les fonctionnalités principales du langage lui-même.

Vincent Ramdhanie
la source
3
Pas toujours. PHPà titre d'exemple, il n'y a guère de différence entre ses vastes fonctions linguistiques et la langue elle-même.
Vahid Amiri
15
Je ne prendrais pas PHP comme exemple d'un langage simple
DrBreakalot
3
@DrBreakalot PHP est un langage extrêmement simple. Cela ne veut pas dire qu'il a une conception cohérente, mais c'est un autre problème.
Courses de légèreté avec Monica le
19
@LightnessRacesinOrbit Je n'appellerais pas du tout PHP "simple": il a un système d'objets basé sur les classes, un ensemble séparé de "valeurs primitives", des fonctions autonomes, des fermetures de première classe construites sur le système d'objets, un mécanisme d'espace de noms, divers notions dites « statiques », les déclarations ainsi que les expressions, include, requireet require_once, si / pour / while (programmation structurée), exceptions, un système distinct des « valeurs d'erreur », les règles de typage faible compliquées, les règles opérateur de priorité compliqué, et ainsi de suite . Comparez cela à la simplicité de, disons, Smalltalk, Scheme, Prolog, Forth, etc.;)
Warbo
3
La raison principale, qui est suggérée mais non explicitement indiquée dans cette réponse, est qu'en gardant le langage aussi simple que possible, il est beaucoup plus facile à implémenter sur d'autres plateformes. Étant donné que les bibliothèques standard sont généralement écrites dans la langue elle - même , elles peuvent être portées de manière triviale.
BlueRaja - Danny Pflughoeft
34

En plus de ce que les autres réponses ont déjà dit, mettre des fonctions standard dans une bibliothèque est une séparation des préoccupations :

  • C'est le travail du compilateur d'analyser le langage et de générer du code pour celui-ci. Ce n'est pas le travail du compilateur de contenir tout ce qui peut déjà être écrit dans cette langue et fourni sous forme de bibliothèque.

  • C'est le travail de la bibliothèque standard (celui qui est toujours implicitement disponible) pour fournir les fonctionnalités de base nécessaires à pratiquement tous les programmes. Ce n'est pas le travail de la bibliothèque standard de contenir toutes les fonctions qui pourraient être utiles.

  • C'est le travail des bibliothèques standard en option de fournir des fonctionnalités auxiliaires dont de nombreux programmes peuvent se passer, mais qui sont encore assez basiques et également essentielles pour de nombreuses applications pour garantir la livraison dans des environnements standard. Ce n'est pas le travail de ces bibliothèques optionnelles de contenir tout le code réutilisable qui a jamais été écrit.

  • C'est le travail des bibliothèques utilisateur de fournir des collections de fonctions réutilisables utiles. Ce n'est pas le travail des bibliothèques utilisateur de contenir tout le code jamais écrit.

  • C'est le travail du code source d'une application de fournir les bits de code restants qui ne sont vraiment pertinents que pour cette application.

Si vous voulez un logiciel unique, vous obtenez quelque chose de incroyablement complexe. Vous devez modulariser pour réduire la complexité à des niveaux gérables. Et vous devez modulariser pour permettre des implémentations partielles :

  • La bibliothèque de threading ne vaut rien sur le contrôleur intégré à cœur unique. Permettre à l'implémentation du langage pour ce contrôleur intégré de ne pas inclure la pthreadbibliothèque est juste la bonne chose à faire.

  • La bibliothèque mathématique ne vaut rien sur le micro-contrôleur qui n'a même pas de FPU. Encore une fois, ne pas être obligé de fournir des fonctions telles que sin()rend la vie beaucoup plus facile pour les implémenteurs de votre langage pour ce microcontrôleur.

  • Même la bibliothèque standard de base n'a aucune valeur lorsque vous programmez un noyau. Vous ne pouvez pas implémenter write()sans syscall dans le noyau et vous ne pouvez pas implémenter printf()sans write(). En tant que programmeur du noyau, c'est votre travail de fournir l' write()appel système, vous ne pouvez pas vous attendre à ce qu'il soit là.

Un langage qui ne permet pas de telles omissions dans les bibliothèques standard n'est tout simplement pas adapté à de nombreuses tâches . Si vous souhaitez que votre langue soit utilisable de manière flexible dans des environnements inhabituels, elle doit être flexible dans les bibliothèques standard incluses. Plus votre langage s'appuie sur des bibliothèques standard, plus il fait d'hypothèses sur son environnement d'exécution, et restreint ainsi son utilisation aux environnements qui fournissent ces prérequis.

Bien sûr, les langages de haut niveau comme python et java peuvent faire beaucoup d'hypothèses sur leur environnement. Et ils ont tendance à inclure beaucoup, beaucoup de choses dans leurs bibliothèques standard. Les langages de niveau inférieur comme C fournissent beaucoup moins dans leurs bibliothèques standard et gardent la bibliothèque standard de base beaucoup plus petite. C'est pourquoi vous trouvez un compilateur C fonctionnel pour pratiquement n'importe quelle architecture, mais vous ne pourrez peut-être pas exécuter de scripts python dessus.

cmaster
la source
16

Une raison importante pour laquelle les compilateurs et les bibliothèques standard sont séparés est parce qu'ils servent deux objectifs différents (même s'ils sont tous deux définis par la même spécification de langage): le compilateur traduit le code de niveau supérieur en instructions machine, et la bibliothèque standard fournit des tests pré-testés implémentations de fonctionnalités couramment nécessaires. Les rédacteurs du compilateur apprécient la modularité comme les autres développeurs de logiciels. En fait, certains des premiers compilateurs C ont encore divisé le compilateur en programmes distincts pour le prétraitement, la compilation et la liaison.

Cette modularité vous offre de nombreux avantages:

  • Il minimise la quantité de travail nécessaire lors de la prise en charge d'une nouvelle plate-forme matérielle, car la plupart du code de bibliothèque standard est indépendant du matériel peut être réutilisé.
  • Une implémentation de bibliothèque standard peut être optimisée de différentes manières (pour la vitesse, l'espace, l'utilisation des ressources, etc.). De nombreux systèmes informatiques antérieurs ne disposaient que d'un seul compilateur, et le fait d'avoir une bibliothèque standard séparée signifiait que les développeurs pouvaient échanger les implémentations en fonction de leurs besoins.
  • La fonctionnalité de bibliothèque standard n'a même pas besoin d'exister. Lorsque vous écrivez du code C nu par exemple, vous avez un compilateur complet mais la plupart des fonctionnalités de bibliothèque standard ne sont pas là et certaines choses comme les E / S de fichiers ne sont même pas possibles. Si le compilateur était requis pour implémenter cette fonctionnalité, vous ne pouviez pas disposer d'un compilateur C conforme aux normes sur certaines des plates-formes où vous en avez le plus besoin.
  • Sur les premiers systèmes, les compilateurs étaient fréquemment développés par la société qui a conçu le matériel. Les bibliothèques standard étaient fréquemment fournies par le fournisseur du système d'exploitation, car elles nécessitaient souvent l'accès à des fonctionnalités (comme les appels système) spécifiques à cette plate-forme logicielle. Il n'était pas pratique pour un rédacteur de compilateur de devoir prendre en charge toutes les différentes combinaisons de matériel et de logiciel (il y avait auparavant beaucoup plus de variété à la fois dans l'architecture matérielle et la plate-forme logicielle).
  • Dans les langages de haut niveau, une bibliothèque standard peut être implémentée en tant que bibliothèque chargée dynamiquement. Une implémentation de bibliothèque standard peut ensuite être utilisée par plusieurs compilateurs et / ou langages de programmation.

Historiquement parlant (du moins du point de vue de C), les versions originales de pré-standardisation du langage n'avaient pas du tout de bibliothèque standard. Les fournisseurs de systèmes d'exploitation et les tiers fournissaient souvent des bibliothèques pleines de fonctionnalités couramment utilisées, mais les différentes implémentations incluaient des choses différentes et elles étaient largement incompatibles entre elles. Lorsque C a été normalisé, ils ont défini une «bibliothèque standard» afin d'harmoniser ces implémentations disparates et d'améliorer la portabilité. La bibliothèque standard C développée séparément du langage, comme les bibliothèques Boost pour C ++, mais ont ensuite été intégrées dans la spécification du langage.

bta
la source
6

Réponse complémentaire au cas d'angle: gestion de la propriété intellectuelle

Un exemple notable est l' implémentation de Math.Pow (double, double) dans .NET Framework qui a été acheté par Microsoft auprès d'Intel et reste non divulgué même si le cadre est devenu open-source. (Pour être précis, dans le cas ci-dessus, il s'agit d'un appel interne plutôt que d'une bibliothèque, mais l'idée tient.) Une bibliothèque séparée de la langue elle-même (théoriquement aussi un sous-ensemble de bibliothèques standard) peut donner aux bailleurs de langue plus de flexibilité pour dessiner le ligne entre ce qui doit rester transparent et ce qui ne doit pas être divulgué (en raison de leurs contrats avec des tiers ou pour d'autres raisons liées à la propriété intellectuelle).

miroxlav
la source
Ceci est déroutant. La page vers laquelle vous liez Math.Powne mentionne aucun achat, ni rien sur Intel, et parle de personnes lisant le code source de la mise en œuvre de la fonction.
Courses de légèreté avec Monica le
@LightnessRacesinOrbit - hm, je peux toujours le voir là (lors de la recherche de "intel"). Vous pouvez également trouver la référence au code source récent (dans les commentaires les plus récents) et également une implémentation alternative (dans la deuxième réponse) qui est accessible au public mais la complexité et l'inefficacité commentée donnent une indication pourquoi l'implémentation originale n'est toujours pas divulguée. Une mise en œuvre vraiment efficace peut nécessiter une connaissance approfondie de nombreux détails au niveau du processeur qui ne sont pas nécessairement disponibles dans le domaine public.
miroxlav
5

Bugs et débogage.

Bogues: Tous les logiciels ont des bogues, votre bibliothèque standard a des bogues et votre compilateur a des bogues. En tant qu'utilisateur de la langue, il est beaucoup plus facile de trouver et de contourner ces bogues lorsqu'ils se trouvent dans la bibliothèque standard plutôt que dans le compilateur.

Débogage: il est beaucoup plus facile pour moi de voir une trace de pile d'une bibliothèque standard et de me donner une idée de ce qui pourrait mal se passer. Parce que cette trace de pile a du code que je comprends. Bien sûr, vous pouvez creuser plus profondément et vous pouvez également retracer vos fonctions intrinsèques, mais c'est beaucoup plus facile si c'est dans une langue que vous utilisez tout le temps de jour en jour.

Pieter B
la source
5

Ceci est une excellente question!

L'état de l'art

Le standard C ++, par exemple, ne spécifie jamais ce qui doit être implémenté dans le compilateur ou dans la bibliothèque standard: il fait simplement référence à l'implémentation . Par exemple, les symboles réservés sont définis à la fois par le compilateur (comme intrinsèques) et par la bibliothèque standard, de manière interchangeable.

Pourtant, toutes les implémentations C ++ que je connais auront le nombre minimum possible d'intrinsèques fourni par le compilateur, et autant que possible fourni par la bibliothèque standard.

Ainsi, bien qu'il soit techniquement possible de définir la bibliothèque standard en tant que fonctionnalité intrinsèque dans le compilateur, elle semble rarement utilisée dans la pratique.

Pourquoi?

Examinons l'idée de déplacer un élément de fonctionnalité de la bibliothèque standard vers le compilateur.

Avantages:

  • De meilleurs diagnostics: les intrinsèques peuvent être dans un boîtier spécial.
  • Meilleures performances: les intrinsèques peuvent être dans un boîtier spécial.

Désavantages:

  • Augmentation de la masse du compilateur: chaque cas spécial ajoute de la complexité au compilateur; la complexité augmente les coûts de maintenance et la probabilité de bugs.
  • Itération plus lente: changer l'implémentation de la fonctionnalité nécessite de changer le compilateur lui-même, ce qui rend plus difficile la création d'une petite bibliothèque (en dehors de std) à expérimenter.
  • Barre d'entrée plus élevée: plus il est cher / difficile de changer quelque chose, moins il y a de chances que les gens s'y joignent.

Cela signifie que déplacer quelque chose vers le compilateur coûte cher , maintenant et à l'avenir, et nécessite donc un boîtier solide. Pour certaines fonctionnalités, il est nécessaire (elles ne peuvent pas être écrites en tant que code normal), mais même alors, il est avantageux d'extraire des pièces minimales et génériques pour les déplacer vers le compilateur et les construire au-dessus dans la bibliothèque standard.

Matthieu M.
la source
5

En tant que concepteur de langues moi-même, je voudrais faire écho à certaines des autres réponses ici, mais les fournir à travers les yeux de quelqu'un qui construit une langue.

Une API n'est pas terminée lorsque vous avez terminé d'y ajouter tout ce que vous pouvez. Une API est terminée lorsque vous avez fini d'en retirer tout ce que vous pouvez.

Un langage de programmation doit être spécifié en utilisant un certain langage. Vous devez être en mesure de transmettre le sens de tout programme écrit dans votre langue. Cette langue est très difficile à écrire et encore plus difficile à bien écrire. En général, il s'agit d'une forme d'anglais très précise et bien structurée utilisée pour transmettre du sens non pas à l'ordinateur, mais à d'autres développeurs, en particulier ceux qui écrivent des compilateurs ou des interprètes pour votre langue. Voici un exemple de la spécification C ++ 11, [intro.multithread / 14]:

La séquence visible d'effets secondaires sur un objet atomique M, par rapport à un calcul de valeur B de M, est une sous-séquence contiguë maximale d'effets secondaires dans l'ordre de modification de M, où le premier effet secondaire est visible par rapport à B , et pour chaque effet secondaire, ce n'est pas le cas que B arrive avant lui. La valeur d'un objet atomique M, telle que déterminée par l'évaluation B, doit être la valeur stockée par une opération dans la séquence visible de M par rapport à B. [Remarque: On peut montrer que la séquence visible d'effets secondaires d'une valeur le calcul est unique compte tenu des exigences de cohérence ci-dessous. —Fin note]

Blek! Quiconque a franchi le pas pour comprendre comment le C ++ 11 gère le multithreading peut comprendre pourquoi le libellé doit être si opaque, mais cela ne pardonne pas le fait qu'il est ... eh bien ... si opaque!

Comparez cela avec la définition de std::shared_ptr<T>::reset, dans la section bibliothèque de la norme:

template <class Y> void reset(Y* p);

Effets: équivalent àshared_ptr(p).swap(*this)

Alors quelle est la différence? Dans la partie définition du langage, les auteurs ne peuvent pas supposer que le lecteur comprend les primitives du langage. Tout doit être précisé soigneusement en prose anglaise. Une fois que nous arrivons à la partie de définition de bibliothèque, nous pouvons utiliser le langage pour spécifier le comportement. C'est souvent beaucoup plus facile!

En principe, on pourrait avoir une accumulation en douceur à partir des primitives au début du document de spécification, tout au long de la définition de ce que nous pourrions considérer comme des «fonctionnalités de bibliothèque standard», sans avoir à tracer une ligne entre les «primitives de langage» et fonctionnalités "bibliothèque standard". En pratique, cette ligne s'avère extrêmement utile à tracer car elle vous permet d'écrire certaines des parties les plus complexes du langage (telles que celles qui doivent implémenter des algorithmes) en utilisant un langage conçu pour les exprimer.

Et nous voyons en effet des lignes floues:

  • En Java, nejava.lang.ref.Reference<T> peut être sous-classé que par les classes de bibliothèque standard et parce que les comportements dejava.lang.ref.WeakReference<T> java.lang.ref.SoftReference<T>java.lang.ref.PhantomReference<T>Reference sont si profondément liés à la spécification du langage Java qu'ils ont dû mettre des restrictions dans la partie de ce processus implémentée en tant que classes de "bibliothèque standard".
  • En C #, il existe une classe, System.Delegate qui encapsule le concept de délégués. Malgré son nom, ce n'est pas un délégué. Il s'agit également d'une classe abstraite (ne peut pas être instanciée) à partir de laquelle vous ne pouvez pas créer de classes dérivées. Seul le système peut le faire grâce à des fonctionnalités écrites dans la spécification du langage.
Cort Ammon - Rétablir Monica
la source
2

Ceci est censé être un ajout aux réponses existantes (et est trop long pour un commentaire).

Il existe au moins deux autres raisons pour une bibliothèque standard:

Barrière à l'entrée

Si une fonction linguistique particulière se trouve dans une fonction de bibliothèque et que je veux savoir comment cela fonctionne, je peux simplement lire la source de cette fonction. Si je veux soumettre un rapport de bogue / patch / demande d'extraction, il n'est généralement pas trop difficile de coder un correctif et des cas de test. Si c'est dans le compilateur, je dois pouvoir creuser dans les internes. Même s'il est dans le même langage (et il devrait l'être, tout compilateur qui se respecte devrait être auto-hébergé), le code du compilateur ne ressemble en rien au code d'application. Cela peut prendre une éternité pour même trouver les bons fichiers.

Vous vous coupez de beaucoup de contributeurs potentiels si vous suivez cette voie.

Chargement de code à chaud

De nombreuses langues offrent cette fonctionnalité à un degré ou un autre, mais il serait extrêmement compliqué de recharger à chaud le code qui effectue le rechargement à chaud. Si la SL est distincte du runtime, elle peut être rechargée.

Jared Smith
la source
3
"tout compilateur qui se respecte devrait être auto-hébergé" - pas du tout. Il serait inutile d'avoir des versions de disons LLVM écrites en C, C ++, Objective-C, Swift, Fortran et ainsi de suite pour compiler tous ces langages.
gnasher729
@ gnasher729 n'est-ce pas un cas particulier (avec d'autres cibles multilingues comme le CLR)?
Jared Smith
@JaredSmith Je dirais que c'est maintenant le cas général, pas spécial du tout. Personne n'écrit plus "un compilateur" comme une application monolithique. Ils produisent plutôt des systèmes de compilation . La plupart des fonctionnalités du compilateur complet sont complètement indépendantes de la langue particulière qui est compilée, et une grande partie de la partie dépendante de la langue peut être effectuée en fournissant différentes données définissant la grammaire de la langue, pas en écrivant un code différent pour chaque langue que vous voulez compiler.
alephzero
2

C'est une question intéressante mais il y a déjà beaucoup de bonnes réponses, donc je ne tenterai pas une réponse complète.

Cependant, deux choses qui, selon moi, n'ont pas suffisamment retenu l'attention:

Premièrement, le tout n'est pas très clair. C'est un peu un spectre exactement parce qu'il y a des raisons de faire les choses différemment. Par exemple, les compilateurs connaissent souvent les bibliothèques standard et leurs fonctions. Exemple de l'exemple: la fonction "Hello World" de C - printf - est la meilleure à laquelle je puisse penser. C'est une fonction de bibliothèque, elle doit l'être, car elle dépend beaucoup de la plate-forme. Mais son comportement (défini par l'implémentation) doit être connu du compilateur afin d'avertir le programmeur des mauvaises invocations. Ce n'est pas particulièrement soigné, mais a été considéré comme un bon compromis. Soit dit en passant, c'est la vraie réponse à la plupart des questions «pourquoi cette conception»: beaucoup de compromis et «semblait être une bonne idée à l'époque». Pas toujours le "c'était la façon claire de le faire" ou "

Deuxièmement, cela permet à la bibliothèque standard de ne pas être toute cette norme. Il y a beaucoup de situations où une langue est souhaitable, mais les bibliothèques standard qui les accompagnent généralement ne sont pas à la fois pratiques et souhaitables. C'est le plus souvent le cas avec des langages de programmation de systèmes comme C, sur des plateformes non standard. Par exemple, si vous avez un système sans OS ni planificateur: vous n'aurez pas de thread.

Avec un modèle de bibliothèque standard (et le threading étant pris en charge), cela peut être géré proprement: le compilateur est à peu près le même, vous pouvez réutiliser les bits des bibliothèques qui s'appliquent, et tout ce que vous ne pouvez pas supprimer. Si cela est intégré au compilateur, les choses commencent à devenir désordonnées.

Par exemple:

  • Vous ne pouvez pas être un compilateur conforme.

  • Comment indiqueriez-vous votre écart par rapport à la norme. Notez qu'il y a généralement une forme de syntaxe d'importation / inclusion que vous pouvez avoir, c'est-à-dire l'importation de pythons ou l'inclusion de C qui pointe facilement vers le problème s'il manque quelque chose dans le modèle de bibliothèque standard.

Des problèmes similaires s'appliquent également si vous souhaitez modifier ou étendre la fonctionnalité de «bibliothèque». C'est beaucoup plus courant que vous ne le pensez. Juste pour s'en tenir au threading: Windows, Linux et certaines unités de traitement de réseau exotiques font tous du threading très différemment. Alors que les bits linux / windows peuvent être assez statiques et pouvoir utiliser une API identique, le contenu NPU changera avec le jour de la semaine et l'API avec lui. Les compilateurs dévieraient rapidement au fur et à mesure que les gens décideraient quels bits ils devraient prendre en charge / pourraient faire sans assez rapidement s'il n'y avait aucun moyen de séparer ce genre de chose.

drjpizzle
la source