Ich dachte, warum gibt es (in allen Programmiersprachen, die ich gelernt habe, wie C ++, Java, Python) Standardbibliotheken wie stdlib, anstatt ähnliche "Funktionen" zu haben, die ein Grundelement der Sprache selbst sind.
programming-languages
standard-library
Simone Broili
quelle
quelle
Antworten:
Lassen Sie mich die gute Antwort von @ Vincent (+1) etwas näher erläutern :
Es kann und tut dies über mindestens zwei Mechanismen:
Inlining eines Funktionsaufrufs - Während der Übersetzung kann der Compiler einen Quellcodeaufruf mit seiner Implementierung direkt inline ersetzen, anstatt die Funktion tatsächlich aufzurufen. Trotzdem muss für die Funktion irgendwo eine Implementierung definiert sein, die sich in der Standardbibliothek befinden kann.
intrinsische Funktion - intrinsische Funktionen sind Funktionen, über die der Compiler informiert wurde, ohne dass die Funktion in einer Bibliothek gefunden werden muss. Diese sind normalerweise für Hardwarefunktionen reserviert, auf die auf andere Weise praktisch nicht zugegriffen werden kann, da sie so einfach sind, dass selbst der Aufwand für den Aufruf der Assembler-Bibliotheksfunktion als hoch angesehen wird. (Der Compiler kann im Allgemeinen nur automatisch Quellcode in seiner Sprache einbinden, nicht jedoch Assembly-Funktionen. Hier kommt der eigentliche Mechanismus ins Spiel.)
Trotzdem ist es manchmal die beste Option für den Compiler, einen Funktionsaufruf in der Quellsprache in einen Funktionsaufruf im Maschinencode zu übersetzen. Rekursion, virtuelle Methoden und reine Größe sind einige Gründe, warum Inlining nicht immer möglich / praktisch ist. (Ein weiterer Grund ist die Absicht des Builds, z. B. separate Kompilierung (Objektmodule), separate Ladeeinheiten (z. B. DLLs)).
Es hat keinen wirklichen Vorteil, die meisten Standardbibliotheksfunktionen in den Griff zu bekommen (das würde viel mehr Wissen in den Compiler einschleusen, ohne einen wirklichen Vorteil zu erzielen), daher ist ein erneuter Aufruf des Maschinencodes häufig am besten geeignet.
C ist eine bemerkenswerte Sprache, die wohl andere explizite Sprachanweisungen zugunsten von Standardbibliotheksfunktionen weggelassen hat. Obwohl es bereits Bibliotheken gab, verlagerte sich diese Sprache dahingehend, mehr Arbeit von Standard-Bibliotheksfunktionen und weniger als explizite Aussagen in der Grammatik der Sprache zu leisten. Beispielsweise wurde IO in anderen Sprachen häufig eine eigene Syntax in Form verschiedener Anweisungen gegeben, während die C-Grammatik keine IO-Anweisungen definiert, sondern sich einfach auf ihre Standardbibliothek bezieht, um dies zu ermöglichen, die alle über Funktionsaufrufe zugänglich sind Der Compiler weiß bereits, wie es geht.
quelle
print
: In 2.x war es eine Anweisung mit einer eigenen speziellen Grammatik, aber in 3.x wurde es nur ein weiterer Funktionsaufruf. Siehe PEP 3105 für die offizielle Erklärung.Dies ist einfach, um die Sprache selbst so einfach wie möglich zu halten. Sie müssen zwischen einer Funktion der Sprache, z. B. einer Art Schleife oder Möglichkeiten zum Übergeben von Parametern an Funktionen usw., und allgemeinen Funktionen, die die meisten Anwendungen benötigen, unterscheiden.
Bibliotheken sind Funktionen, die für viele Programmierer nützlich sein können, sodass sie als wiederverwendbarer Code erstellt werden, der gemeinsam genutzt werden kann. Die Standardbibliotheken sind so konzipiert, dass sie häufig von Programmierern benötigte Funktionen darstellen. Auf diese Weise ist die Programmiersprache für ein breiteres Spektrum von Programmierern sofort nützlich. Die Bibliotheken können aktualisiert und erweitert werden, ohne die Kernfunktionen der Sprache selbst zu ändern.
quelle
PHP
Beispielsweise macht es kaum einen Unterschied zwischen seinen umfangreichen Sprachfunktionen und der Sprache selbst.include
,require
undrequire_once
, wenn / for / while (strukturierte Programmierung), Ausnahmen, ein separates System von ‚Fehlerwerte‘ schwache Typisierung Regeln kompliziert, Betreiber Vorrangregeln kompliziert, und so weiter . Vergleichen Sie dies mit der Einfachheit von beispielsweise Smalltalk, Schema, Prolog, Forth usw.;)Zusätzlich zu den anderen Antworten ist das Einfügen von Standardfunktionen in eine Bibliothek eine Trennung von Bedenken :
Es ist die Aufgabe des Compilers, die Sprache zu analysieren und Code dafür zu generieren. Es ist nicht die Aufgabe des Compilers, irgendetwas zu enthalten, das bereits in dieser Sprache geschrieben und als Bibliothek bereitgestellt werden kann.
Dies ist die Aufgabe der Standardbibliothek (die immer implizit verfügbar ist), um die Kernfunktionalität bereitzustellen , die von praktisch allen Programmen benötigt wird. Es ist nicht die Aufgabe der Standardbibliothek, alle Funktionen zu enthalten, die nützlich sein könnten.
Optionale Standardbibliotheken haben die Aufgabe, Zusatzfunktionen bereitzustellen, auf die viele Programme verzichten können, die jedoch immer noch recht einfach und für viele Anwendungen unerlässlich sind, um den Versand in Standardumgebungen zu gewährleisten. Es ist nicht die Aufgabe dieser optionalen Bibliotheken, den gesamten wiederverwendbaren Code zu enthalten, der jemals geschrieben wurde.
Es ist Aufgabe der Benutzerbibliotheken, Sammlungen nützlicher wiederverwendbarer Funktionen bereitzustellen. Es ist nicht die Aufgabe von Benutzerbibliotheken, den gesamten Code zu enthalten, der jemals geschrieben wurde.
Es ist die Aufgabe des Quellcodes einer Anwendung, die verbleibenden Codebits bereitzustellen, die wirklich nur für diese eine Anwendung relevant sind.
Wenn Sie eine einheitliche Software suchen, bekommen Sie etwas wahnsinnig Komplexes. Sie müssen modularisieren, um die Komplexität auf ein überschaubares Maß zu reduzieren. Und Sie müssen modularisieren , damit Teil Implementierungen:
Die Threading-Bibliothek ist auf dem Single-Core-Embedded-Controller wertlos. Es
pthread
ist genau das Richtige, zuzulassen, dass die Sprachimplementierung für diesen eingebetteten Controller die Bibliothek nicht einbezieht.Die Mathematikbibliothek ist auf dem Mikrocontroller ohne FPU wertlos. Auch hier
sin()
macht es den Implementierern Ihrer Sprache das Leben für diesen Mikrocontroller sehr viel einfacher , nicht gezwungen zu sein, Funktionen wie bereitzustellen .Selbst die Standard-Kernbibliothek ist wertlos, wenn Sie einen Kernel programmieren. Sie können nicht
write()
ohne einen Systemaufruf in den Kernel implementieren, und Sie können nichtprintf()
ohne implementierenwrite()
. Als Kernel-Programmierer ist es Ihre Aufgabe, denwrite()
Syscall bereitzustellen . Sie können nicht einfach erwarten, dass er da ist.Eine Sprache, die solche Auslassungen in den Standardbibliotheken nicht zulässt, ist für viele Aufgaben einfach nicht geeignet . Wenn Sie möchten, dass Ihre Sprache in ungewöhnlichen Umgebungen flexibel verwendet werden kann, muss sie in den enthaltenen Standardbibliotheken flexibel sein. Je mehr sich Ihre Sprache auf Standardbibliotheken stützt, desto mehr Annahmen werden in Bezug auf die Ausführungsumgebung getroffen und daher auf Umgebungen beschränkt, die diese Voraussetzungen erfüllen.
Natürlich können Hochsprachen wie Python und Java eine Menge Annahmen über ihre Umgebung machen. Und sie neigen dazu, viele, viele Dinge in ihre Standardbibliotheken aufzunehmen. Untergeordnete Sprachen wie C stellen in ihren Standardbibliotheken viel weniger zur Verfügung und halten die Kernstandardbibliothek viel kleiner. Aus diesem Grund finden Sie einen funktionierenden C-Compiler für praktisch jede Architektur, der jedoch möglicherweise keine Python-Skripte ausführen kann.
quelle
Ein wichtiger Grund für die Trennung von Compilern und Standardbibliotheken besteht darin, dass sie zwei unterschiedlichen Zwecken dienen (auch wenn beide durch dieselbe Sprachspezifikation definiert sind): Der Compiler übersetzt Code höherer Ebene in Maschinenanweisungen, und die Standardbibliothek bietet vorab getestete Funktionen Implementierungen von häufig benötigten Funktionen. Compiler-Autoren legen genau wie andere Software-Entwickler Wert auf Modularität. Einige der frühen C-Compiler haben den Compiler sogar in separate Programme zur Vorverarbeitung, Kompilierung und Verknüpfung aufgeteilt.
Diese Modularität bietet Ihnen eine Reihe von Vorteilen:
Historisch gesehen (zumindest aus Sicht von C) hatten die ursprünglichen Vorstandardisierungsversionen der Sprache überhaupt keine Standardbibliothek. Betriebssystemhersteller und Drittanbieter stellten häufig Bibliotheken mit häufig verwendeten Funktionen zur Verfügung. Unterschiedliche Implementierungen umfassten jedoch unterschiedliche Aspekte und waren weitgehend inkompatibel. Als C standardisiert wurde, definierten sie eine "Standardbibliothek", um diese unterschiedlichen Implementierungen zu harmonisieren und die Portabilität zu verbessern. Die C-Standardbibliothek wurde unabhängig von der Sprache entwickelt, wie die Boost-Bibliotheken für C ++, wurden aber später in die Sprachspezifikation integriert.
quelle
Zusätzliche Eckantwort: Intellectual Property Management
Ein bemerkenswertes Beispiel ist die Implementierung von Math.Pow (double, double) in .NET Framework, das von Microsoft von Intel gekauft wurde und auch dann nicht veröffentlicht wird, wenn das Framework Open Source ist. (Um genau zu sein, im obigen Fall handelt es sich nicht um eine Bibliothek, sondern um einen internen Aufruf.) Eine von der Sprache selbst getrennte Bibliothek (theoretisch auch eine Teilmenge von Standardbibliotheken) kann den Unterstützern der Sprache mehr Flexibilität beim Zeichnen der zwischen dem, was transparent zu halten ist, und dem, was geheim zu halten ist (aufgrund von Verträgen mit Dritten oder aus anderen Gründen des geistigen Eigentums).
quelle
Math.Pow
erstellen, wird weder ein Kauf noch etwas über Intel erwähnt. Es handelt sich um Personen, die den Quellcode für die Implementierung der Funktion lesen.Bugs und Debugging.
Bugs: Alle Software hat Bugs, Ihre Standardbibliothek hat Bugs und Ihr Compiler hat Bugs. Als Benutzer der Sprache ist es viel einfacher, solche Fehler zu finden und zu umgehen, wenn sie in der Standardbibliothek und nicht im Compiler vorhanden sind.
Debugging: Es ist für mich viel einfacher, einen Stack-Trace einer Standardbibliothek zu sehen und mir ein Gefühl dafür zu geben, was möglicherweise schief geht. Weil diese Stapelverfolgung Code hat, verstehe ich. Natürlich können Sie tiefer graben und Ihre inneren Funktionen nachvollziehen, aber es ist viel einfacher, wenn Sie eine Sprache verwenden, die Sie von Tag zu Tag verwenden.
quelle
Das ist eine ausgezeichnete Frage!
Der letzte Stand der Technik
Der C ++ - Standard gibt beispielsweise niemals an, was im Compiler oder in der Standardbibliothek implementiert werden soll: Er bezieht sich nur auf die Implementierung . Beispielsweise werden reservierte Symbole sowohl vom Compiler als auch von der Standardbibliothek austauschbar definiert.
Alle mir bekannten C ++ - Implementierungen haben jedoch die geringstmögliche Anzahl von vom Compiler bereitgestellten Inhalten und so viel wie möglich von der Standardbibliothek.
Obwohl es technisch machbar ist, die Standardbibliothek im Compiler als intrinsische Funktionalität zu definieren, scheint sie in der Praxis selten verwendet zu werden.
Warum?
Betrachten wir die Idee, einige Funktionen aus der Standardbibliothek in den Compiler zu verschieben.
Vorteile:
Nachteile:
std
) zum Experimentieren zu erstellen .Dies bedeutet, dass das Verschieben von Daten in den Compiler jetzt und in Zukunft teuer ist und daher einen soliden Fall erfordert. Für einige Funktionen ist es erforderlich (sie können nicht als regulärer Code geschrieben werden), aber selbst dann lohnt es sich, minimale und generische Teile zu extrahieren , um sie in den Compiler zu verschieben und in der Standardbibliothek darauf zu erstellen.
quelle
Als Sprachdesigner möchte ich einige der anderen Antworten hier wiederholen, sie aber mit den Augen von jemandem zur Verfügung stellen, der eine Sprache aufbaut.
Eine Programmiersprache muss in einer Sprache angegeben werden. Sie müssen in der Lage sein, die Bedeutung eines in Ihrer Sprache geschriebenen Programms zu vermitteln. Diese Sprache ist sehr schwer zu schreiben und noch schwerer gut zu schreiben. Im Allgemeinen ist es eine sehr präzise und gut strukturierte Form des Englischen, die verwendet wird, um nicht dem Computer, sondern anderen Entwicklern, insbesondere den Entwicklern, die Compiler oder Interpreten für Ihre Sprache schreiben, Bedeutung zu vermitteln. Hier ist ein Beispiel aus der C ++ 11-Spezifikation [intro.multithread / 14]:
Blek! Jeder, der es verstanden hat, wie C ++ 11 mit Multithreading umgeht, kann verstehen, warum der Wortlaut so undurchsichtig sein muss, aber das verzeiht nicht, dass er ... na ja ... so undurchsichtig ist!
Vergleichen Sie dies mit der Definition von
std::shared_ptr<T>::reset
im Abschnitt Bibliothek des Standards:Was ist der Unterschied? Im Sprachdefinitionsteil können die Autoren nicht davon ausgehen, dass der Leser die Sprachprimitive versteht. Alles muss sorgfältig in englischer Prosa angegeben werden. Sobald wir den Bibliotheksdefinitionsteil erreicht haben, können wir die Sprache verwenden, um das Verhalten festzulegen. Das ist oft viel einfacher!
Grundsätzlich könnte man zu Beginn des Spezifikationsdokuments einen reibungslosen Aufbau von Grundelementen erreichen, indem man definiert, was wir als "Standardbibliotheksfunktionen" betrachten, ohne eine Grenze zwischen "Sprachgrundelementen" und "Standardbibliotheksfunktionen" ziehen zu müssen "Standard Library" -Funktionen. In der Praxis erweist sich das Zeichnen dieser Linie als äußerst wertvoll, da Sie damit einige der komplexesten Teile der Sprache (z. B. diejenigen, die Algorithmen implementieren müssen) in einer Sprache schreiben können, die sie ausdrücken soll.
Und wir sehen tatsächlich einige verschwommene Linien:
java.lang.ref.Reference<T>
kann es nur von den Standardbibliotheksklassen untergeordnet werden,java.lang.ref.WeakReference<T>
java.lang.ref.SoftReference<T>
undjava.lang.ref.PhantomReference<T>
weil das Verhalten vonReference
so stark mit der Java-Sprachspezifikation verflochten ist, dass sie einige Einschränkungen für den als "Standardbibliotheksklassen" implementierten Teil dieses Prozesses erforderlich machen.quelle
Dies ist als Ergänzung zu den vorhandenen Antworten gedacht (und für einen Kommentar zu lang).
Es gibt mindestens zwei weitere Gründe für eine Standardbibliothek:
Zutrittsschranke
Wenn sich ein bestimmtes Sprachmerkmal in einer Bibliotheksfunktion befindet und ich wissen möchte, wie es funktioniert, kann ich einfach die Quelle für diese Funktion lesen. Wenn ich einen Fehlerbericht / Patch / Pull-Antrag einreichen möchte, ist es im Allgemeinen nicht zu schwierig, einen Fix und Testfall (e) zu codieren. Wenn es im Compiler ist, muss ich in der Lage sein, in die Interna zu graben. Selbst wenn der Compiler in derselben Sprache geschrieben ist (und dies sollte auch so sein), ist er kein Anwendungscode. Es kann ewig dauern, bis die richtigen Dateien gefunden sind.
Sie können sich von vielen potenziellen Mitwirkenden abkoppeln, wenn Sie diesen Weg gehen.
Hot Code wird geladen
Viele Sprachen bieten diese Funktion bis zu einem gewissen Grad an, aber es wäre enorm kompliziert, den Code, der das Hot-Reload ausführt, im laufenden Betrieb neu zu laden. Wenn der SL von der Laufzeit getrennt ist, kann er neu geladen werden.
quelle
Dies ist eine interessante Frage, aber es gibt bereits viele gute Antworten, daher werde ich nicht versuchen, eine vollständige zu beantworten.
Zwei Dinge, von denen ich glaube, dass sie nicht genug Beachtung finden:
Erstens ist das Ganze nicht super übersichtlich. Es ist ein bisschen wie ein Spektrum, weil es Gründe gibt, die Dinge anders zu machen. Beispielsweise kennen Compiler häufig Standardbibliotheken und ihre Funktionen. Beispiel für das Beispiel: Cs "Hello World" -Funktion - printf - ist die beste, die ich mir vorstellen kann. Es ist eine Bibliotheksfunktion, das muss eine Art sein, da es sehr plattformabhängig ist. Das Verhalten (Implementierung definiert) muss dem Compiler jedoch bekannt sein, um den Programmierer vor fehlerhaften Aufrufen zu warnen. Dies ist nicht besonders ordentlich, wurde aber als guter Kompromiss angesehen. Dies ist übrigens die eigentliche Antwort auf die meisten Fragen zum "Warum dieses Design": viel Kompromiss und "schien zu dieser Zeit eine gute Idee zu sein". Nicht immer das "das war der klare Weg, es zu tun" oder "
Zweitens erlaubt es der Standardbibliothek, nicht der ganze Standard zu sein. Es gibt viele Situationen, in denen eine Sprache wünschenswert ist, aber die Standardbibliotheken, die sie normalerweise begleiten, sind nicht sowohl praktisch als auch wünschenswert. Dies ist am häufigsten bei Systemprogrammiersprachen wie C auf nicht standardmäßigen Plattformen der Fall. Wenn Sie beispielsweise ein System ohne Betriebssystem oder Scheduler haben, wird kein Threading durchgeführt.
Mit einem Standardbibliotheksmodell (und dem darin unterstützten Threading) kann dies sauber gehandhabt werden: Der Compiler ist ziemlich gleich, Sie können die Bits der zutreffenden Bibliotheken wiederverwenden und alles, was Sie nicht entfernen können. Wenn dies in den Compiler eingebrannt wird, wird es unordentlich.
Beispielsweise:
Sie können kein kompatibler Compiler sein.
Wie würden Sie Ihre Abweichung vom Standard angeben? Beachten Sie, dass es normalerweise eine Form der Import- / Include-Syntax gibt, bei der ein Fehler auftreten kann, z. B. der Pythons-Import oder das C-Include, die leicht auf das Problem hinweisen, wenn im Standardbibliotheksmodell etwas fehlt.
Ähnliche Probleme treten auch auf, wenn Sie die Bibliotheksfunktionalität optimieren oder erweitern möchten. Dies ist weitaus häufiger als Sie vielleicht denken. Nur um beim Threading zu bleiben: Windows, Linux und einige-exotische-Netzwerk-Prozessor-Einheiten machen das Threading ganz anders. Während die Linux / Windows-Bits möglicherweise ziemlich statisch sind und eine identische API verwenden können, ändert sich das NPU-Zeug mit dem Wochentag und die API mit dieser. Compiler würden schnell davon abweichen, wenn die Leute entschieden, welche Bits sie brauchen, um zu unterstützen / schnell auszusteigen, wenn es keine Möglichkeit gäbe, solche Dinge aufzuteilen.
quelle