Dlaczego standardowe biblioteki nie programują prymitywów językowych? [Zamknięte]

30

Zastanawiałem się, dlaczego istnieją (we wszystkich językach programowania, których się nauczyłem, takich jak C ++, Java, Python) standardowe biblioteki, takie jak stdlib, zamiast mieć podobne „funkcje” będące prymitywem samego języka.

Simone Broili
źródło
4
Co masz na myśli mówiąc „dlaczego kompilator nie mógł po prostu przetłumaczyć wywołania funkcji na zestaw instrukcji”? Z grubsza to robi kompilator, standardowa biblioteka czy nie (Ok, Python tylko częściowo i kod bajtowy Java na JVM; podobna koncepcja). Biblioteki standardowe naprawdę nie mają nic wspólnego z kompilacją kodu -> instrukcji.
Delioth
25
@Delioth Myślę, że Simone pyta, dlaczego nie wszystko w standardowej bibliotece języka $ LANG jest prymitywną konstrukcją / funkcją tego języka. Powiedziałbym, że to rozsądne pytanie dla każdego, kto jest bardzo nowy w programowaniu języków :)
Andres F.
33
Standardowa biblioteka zazwyczaj wypełnia lukę między działającym językiem programowania a przydatnym językiem, z którego będą korzystać ludzie.
Telastyn
6
Znaczna część standardowej biblioteki Pythona jest napisana w C i już skompilowana.
ElmoVanKielmo
1
Dla kontrastu, w większości implementacji BASICa wszystko jest częścią języka i nie ma w ogóle bibliotek ani ich nie obsługuje (z wyjątkiem kilku implementacji, z możliwością wywoływania procedur języka maszynowego).
Euro Micelli

Odpowiedzi:

32

Pozwólcie mi rozwinąć nieco dobrą odpowiedź @ Vincenta (+1) :

Dlaczego kompilator nie mógł po prostu przetłumaczyć wywołania funkcji na zestaw instrukcji?

Może i robi to za pomocą co najmniej dwóch mechanizmów:

  • wstawianie wywołania funkcji - podczas tłumaczenia kompilator może zastąpić wywołanie kodu źródłowego z implementacją bezpośrednio wbudowaną, zamiast rzeczywistego wywołania funkcji. Mimo to funkcja musi mieć gdzieś zdefiniowaną implementację, która może znajdować się w standardowej bibliotece.

  • funkcja wewnętrzna - funkcja wewnętrzna to funkcje, o których poinformowano kompilator, niekoniecznie znajdując funkcję w bibliotece. Zazwyczaj są one zarezerwowane dla funkcji sprzętowych, które nie są praktycznie dostępne w żaden inny sposób, ponieważ są tak proste, że nawet narzut wywołania funkcji biblioteki języka asemblera jest uważany za wysoki. (Kompilator może generalnie tylko automatycznie wstawiać kod źródłowy w swoim języku, ale nie funkcje asemblera, czyli tam, gdzie wchodzi wewnętrzny mechanizm.)

Mimo to, najlepszą opcją jest czasami przetłumaczenie przez kompilator wywołania funkcji w języku źródłowym na wywołanie funkcji w kodzie maszynowym. Rekurencja, metody wirtualne i sama wielkość to niektóre powody, dla których wstawianie nie zawsze jest możliwe / praktyczne. (Innym powodem jest zamiar kompilacji, taki jak osobna kompilacja (moduły obiektowe), osobne jednostki ładujące (np. DLL)).

Nie ma też żadnej realnej przewagi, by większość standardowych funkcji bibliotecznych była intriskami (co znacznie utrudniłoby kompilację wiedzy w kompilatorze, bez żadnej realnej korzyści), dlatego często najbardziej odpowiednie jest ponowne wywołanie kodu maszynowego.

C jest znaczącym językiem, który prawdopodobnie pomija inne jawne instrukcje językowe na korzyść standardowych funkcji bibliotecznych. Choć biblioteki istniały wcześniej, język ten przeszedł do wykonywania większej ilości pracy od standardowych funkcji bibliotecznych, a mniej jako wyraźnych instrukcji w gramatyce języka. Na przykład IO w innych językach często otrzymywało własną składnię w postaci różnych instrukcji, podczas gdy gramatyka C nie definiuje żadnych instrukcji IO, po prostu odkłada na swoją standardową bibliotekę, aby zapewnić, że wszystkie są dostępne poprzez wywołania funkcji, które kompilator już wie, jak to zrobić.

Erik Eidt
źródło
3
Niezła odpowiedź. Należy dodać kilka słów, dlaczego podjęto tę decyzję w C: jeśli dobrze pamiętam, głównym powodem było to, że znacznie ułatwiło tworzenie kompilatorów C dla wielu różnych architektur sprzętowych.
Doc Brown
10
@DocBrown Do 1975 roku było wystarczająco dużo przykładów w dziedzinie rozwoju języka programowania (ALGOL-68, ktoś?), Które pokazały, że próby wprowadzenia wszystkiego do języka bezpośrednio doprowadziły do ​​znacznego spowolnienia zarówno w finalizacji specyfikacji języka, jak i w tworzeniu implementacji językowych.
Joker_vD
5
Podobnym przykładem jest to, co robił Python print: w wersji 2.x była to instrukcja z własną specjalną gramatyką, ale w wersji 3.x stała się tylko kolejnym wywołaniem funkcji. Zobacz PEP 3105 do oficjalnego wyjaśnienia.
dan04
1
@DocBrown, przenośność prawie na pewno nie była powodem. Kiedy powstały Unix i C, zostały one zaprojektowane i zbudowane dla dokładnie jednej maszyny, zapasowej PDP-7, ponieważ Ken Thompson zastanawiał się, jakie koncepcje można uratować z nieudanego projektu Multics. C został również stworzony z jednego powodu: aby mieć język wysokiego poziomu, w którym (re) implementować Uniksa. Są w zasadzie eksperymentem w projektowaniu oprogramowania, a nie poważną próbą komercyjnego wieloplatformowego systemu operacyjnego i języka. Zobacz na przykład bell-labs.com/usr/dmr/www/chist.html .
Euro Micelli
@EuroMicelli: Nie widzę w tym sprzeczności. Twoje referencje zawierają wiele szczegółów na temat tego, kiedy przenośność stała się ważna, tak naprawdę było to we wczesnych latach rozwoju C i Unix. Mogę tylko zgadywać tutaj, ale jeśli wynalazcy C nie utrzymaliby języka celowo na małym poziomie, myślę, że byłoby mało prawdopodobne, aby mogli przenieść go tak szybko i skutecznie na wiele różnych architektur.
Doc Brown
70

Ma to na celu uproszczenie samego języka. Musisz rozróżnić funkcję języka, taką jak rodzaj pętli lub sposoby przekazywania parametrów do funkcji itd., Oraz wspólną funkcjonalność, której potrzebuje większość aplikacji.

Biblioteki to funkcje, które mogą być przydatne dla wielu programistów, dlatego są tworzone jako kod wielokrotnego użytku, który można udostępniać. Standardowe biblioteki są zaprojektowane tak, aby były bardzo powszechnymi funkcjami, których zwykle potrzebują programiści. W ten sposób język programowania jest natychmiast przydatny dla szerszego grona programistów. Biblioteki można aktualizować i rozszerzać bez zmiany podstawowych funkcji samego języka.

Vincent Ramdhanie
źródło
3
Nie zawsze. PHPjako przykład prawie nie robi różnic między jego rozległymi funkcjami językowymi a samym językiem.
Vahid Amiri
15
Nie wziąłbym PHP za przykład prostego języka
DrBreakalot
3
@DrBreakalot PHP to niezwykle prosty język. Nie oznacza to, że ma spójną konstrukcję, ale to kolejny problem.
Lekkość ściga się z Moniką
19
@LightnessRacesinOrbit W ogóle nie nazwałbym PHP „prostym”: ma oparty na klasach system obiektowy, osobny zestaw „prymitywnych wartości”, samodzielne funkcje, najwyższej klasy zamknięcia zbudowane na systemie obiektowym, mechanizm przestrzeni nazw, różne pojęcia zwane „statyczne”, oświadczenia, a także wyrażenia, include, requirei require_once, jeśli / do / while (programowania strukturalnego), wyjątkami, oddzielny system „wartości błędu”, skomplikowane słabe zasady typowania, skomplikowane zasady pierwszeństwa operator, i tak dalej . Porównaj to z prostotą, powiedzmy, Smalltalk, Scheme, Prolog, Forth itp.;)
Warbo
3
Głównym powodem, na który wskazano, ale nie podano wprost w tej odpowiedzi, jest to, że utrzymując język tak prosty, jak to możliwe, znacznie łatwiej jest go wdrożyć na innych platformach. Ponieważ standardowe biblioteki są zwykle pisane w samym języku , można je w prosty sposób przenosić.
BlueRaja - Danny Pflughoeft
34

Oprócz tego, co już powiedzieli inne odpowiedzi, umieszczenie standardowych funkcji w bibliotece to oddzielenie problemów :

  • Kompilatorem jest parsowanie języka i generowanie dla niego kodu. Kompilator nie musi zawierać niczego, co można już napisać w tym języku i udostępnić jako bibliotekę.

  • Jest to zadanie biblioteki standardowej (zawsze domyślnie dostępnej) zapewniające podstawową funkcjonalność, która jest potrzebna praktycznie we wszystkich programach. Zawieranie wszystkich funkcji, które mogą być przydatne, nie jest zadaniem standardowej biblioteki.

  • Zadaniem opcjonalnych bibliotek standardowych jest zapewnienie funkcji pomocniczych, bez których wiele programów może się obejść, ale które są nadal dość podstawowe i również niezbędne w wielu aplikacjach, aby zagwarantować wysyłkę w standardowych środowiskach. Nie jest zadaniem tych opcjonalnych bibliotek przechowywanie całego kodu wielokrotnego użytku, który kiedykolwiek został napisany.

  • Biblioteki użytkowników mają za zadanie udostępniać kolekcje przydatnych funkcji wielokrotnego użytku. Nie jest zadaniem bibliotek użytkownika przechowywanie całego kodu, który kiedykolwiek został napisany.

  • Zadaniem kodu źródłowego aplikacji jest dostarczenie pozostałych fragmentów kodu, które tak naprawdę dotyczą tylko tej jednej aplikacji.

Jeśli potrzebujesz uniwersalnego oprogramowania, otrzymasz coś niesamowicie złożonego. Musisz zmodularyzować, aby zredukować złożoność do możliwych do zarządzania poziomów. Musisz zmodularyzować, aby umożliwić częściowe wdrożenia:

  • Biblioteka wątków jest bezwartościowa na wbudowanym kontrolerze jednordzeniowym. Umożliwienie implementacji języka dla tego wbudowanego kontrolera po prostu nie dołączania pthreadbiblioteki jest właściwym rozwiązaniem.

  • Biblioteka matematyczna jest bezwartościowa na mikrokontrolerze, który nawet nie ma FPU. Ponownie, nie będąc zmuszonym do dostarczania funkcji takich jak sin()życie, jest znacznie łatwiejsze dla implementatorów twojego języka dla tego mikrokontrolera.

  • Nawet podstawowa biblioteka standardowa jest bezwartościowa, gdy programujesz jądro. Nie możesz zaimplementować write()bez syscall w jądrze i nie możesz zaimplementować printf()bez write(). Jako programista jądra Twoim zadaniem jest zapewnić write()wywołanie systemowe, nie możesz po prostu oczekiwać, że będzie ono dostępne.

Język, który nie pozwala na takie pominięcia w standardowych bibliotekach, po prostu nie nadaje się do wielu zadań . Jeśli chcesz, aby Twój język był elastycznie używany w nietypowych środowiskach, musi on być elastyczny w zakresie bibliotek standardowych. Im bardziej twój język opiera się na bibliotekach standardowych, tym więcej przyjmuje założeń dotyczących środowiska wykonawczego, a tym samym ogranicza jego użycie do środowisk, które zapewniają te warunki wstępne.

Oczywiście języki wysokiego poziomu, takie jak Python i Java, mogą przyjmować wiele założeń dotyczących ich środowiska. I zwykle zawierają wiele, wiele rzeczy w swoich standardowych bibliotekach. Języki niższego poziomu, takie jak C, zapewniają znacznie mniej w swoich standardowych bibliotekach i znacznie zmniejszają podstawową bibliotekę standardową. Dlatego znajdujesz działający kompilator C dla praktycznie dowolnej architektury, ale może nie być w stanie uruchomić na nim żadnych skryptów Pythona.

cmaster
źródło
16

Jednym z głównych powodów, dla których kompilatory i biblioteki standardowe są oddzielne, jest to, że służą one dwóm różnym celom (nawet jeśli oba są zdefiniowane przez tę samą specyfikację językową): kompilator tłumaczy kod wyższego poziomu na instrukcje maszynowe, a biblioteka standardowa zapewnia wstępnie przetestowane wdrożenia powszechnie potrzebnej funkcjonalności. Autorzy kompilatorów cenią modułowość, podobnie jak inni twórcy oprogramowania. W rzeczywistości niektóre wczesne kompilatory C dalej dzielą kompilator na osobne programy do wstępnego przetwarzania, kompilacji i łączenia.

Ta modułowość daje wiele zalet:

  • Minimalizuje to ilość pracy potrzebnej do obsługi nowej platformy sprzętowej, ponieważ większość standardowego kodu biblioteki jest niezależna od sprzętu i może być ponownie użyta.
  • Standardową implementację biblioteki można zoptymalizować na różne sposoby (pod kątem szybkości, miejsca, wykorzystania zasobów itp.). Wiele wczesnych systemów obliczeniowych posiadało tylko jeden kompilator, a osobna biblioteka standardowa oznaczała, że ​​programiści mogli zamieniać implementacje na swoje potrzeby.
  • Standardowa funkcjonalność biblioteki nawet nie musi istnieć. Na przykład podczas pisania kodu C bez systemu operacyjnego masz w pełni funkcjonalny kompilator, ale większość standardowych funkcji biblioteki nie istnieje, a niektóre rzeczy, takie jak operacje we / wy pliku, nie są nawet możliwe. Jeśli do implementacji tej funkcji wymagany był kompilator, nie można mieć kompilatora C zgodnego ze standardami na niektórych platformach, na których jest on najbardziej potrzebny.
  • We wczesnych systemach kompilatory były często opracowywane przez firmę, która zaprojektowała sprzęt. Standardowe biblioteki były często dostarczane przez dostawcę systemu operacyjnego, ponieważ często wymagały dostępu do funkcji (takich jak wywołania systemowe) specyficznych dla tej platformy oprogramowania. Pisanie kompilatorów było niepraktyczne, aby obsługiwać wszystkie różne kombinacje sprzętu i oprogramowania (wcześniej była o wiele większa różnorodność zarówno pod względem architektury sprzętu, jak i platformy oprogramowania).
  • W językach wysokiego poziomu biblioteka standardowa może być implementowana jako biblioteka ładowana dynamicznie. Jedna standardowa implementacja biblioteki może być następnie używana przez wiele kompilatorów i / lub języków programowania.

Historycznie rzecz biorąc (przynajmniej z perspektywy C) oryginalne, przednormalizacyjne wersje języka w ogóle nie miały standardowej biblioteki. Dostawcy systemów operacyjnych i firmy zewnętrzne często zapewniały biblioteki pełne często używanych funkcji, ale różne implementacje obejmowały różne rzeczy i były w dużej mierze niekompatybilne ze sobą. Kiedy C zostało znormalizowane, zdefiniowano „standardową bibliotekę”, próbując zharmonizować te odmienne implementacje i poprawić przenośność. Standardowa biblioteka C opracowana oddzielnie od języka, podobnie jak biblioteki Boost dla C ++, ale później zostały zintegrowane ze specyfikacją języka.

bta
źródło
6

Dodatkowa odpowiedź narożna: zarządzanie własnością intelektualną

Godnym uwagi przykładem jest implementacja Math.Pow (double, double) w .NET Framework, który został zakupiony przez Microsoft od Intela i pozostaje nieujawniony, nawet jeśli framework został otwarty. (Mówiąc ściślej, w powyższym przypadku jest to wywołanie wewnętrzne, a nie biblioteka, ale idea się utrzymuje). Biblioteka oddzielona od samego języka (teoretycznie również podzbiór bibliotek standardowych) może dać osobom popierającym język większą elastyczność w rysowaniu granica między tym, co należy zachować przejrzystość, a tym, co musi pozostać niejawne (ze względu na ich umowy ze stronami trzecimi lub inne powody związane z własnością intelektualną).

miroxlav
źródło
To jest mylące. Strona, do której prowadzi link Math.Pow, nie wspomina o żadnym zakupie ani o Intelie i mówi o ludziach czytających kod źródłowy implementacji funkcji.
Wyścigi lekkości z Moniką
@LightnessRacesinOrbit - hm, nadal go widzę (podczas wyszukiwania „intel”). Można również znaleźć odniesienie do ostatniego kodu źródłowego (w najnowszych komentarzach), a także alternatywnej implementacji (w drugiej odpowiedzi), która jest publicznie dostępna, ale jej złożoność i skomentowana nieefektywność daje wskazówkę, dlaczego oryginalna implementacja nadal nie jest ujawniona. Naprawdę wydajne wdrożenie może wymagać dogłębnej znajomości wielu szczegółów na poziomie procesora, które niekoniecznie są dostępne w domenie publicznej.
miroxlav
5

Błędy i debugowanie.

Błędy: całe oprogramowanie zawiera błędy, w standardowej bibliotece występują błędy, a na kompilatorze występują błędy. Jako użytkownik języka znacznie łatwiej jest znaleźć i obejść takie błędy, gdy znajdują się one w standardowej bibliotece, a nie w kompilatorze.

Debugowanie: Znacznie łatwiej jest mi zobaczyć ślad stosu standardowej biblioteki i dać mi poczucie, co może pójść nie tak. Ponieważ ten ślad stosu zawiera kod, który rozumiem. Oczywiście możesz głębiej kopać, a także śledzić swoje wewnętrzne funkcje, ale jest to o wiele łatwiejsze, jeśli używasz języka, którego używasz przez cały dzień.

Pieter B.
źródło
5

To doskonałe pytanie!

Najnowocześniejszy

Na przykład standard C ++ nigdy nie określa, co powinno zostać zaimplementowane w kompilatorze lub w standardowej bibliotece: odnosi się tylko do implementacji . Na przykład symbole zastrzeżone są definiowane zamiennie zarówno przez kompilator (jako elementy wewnętrzne), jak i przez bibliotekę standardową.

Jednak wszystkie implementacje C ++, o których wiem, będą miały minimalną możliwą liczbę elementów wewnętrznych dostarczonych przez kompilator i możliwie jak najwięcej ze standardowej biblioteki.

Zatem, chociaż technicznie wykonalne jest zdefiniowanie biblioteki standardowej jako funkcji wewnętrznej w kompilatorze, wydaje się, że jest rzadko stosowane w praktyce.

Czemu?

Rozważmy pomysł przeniesienia części funkcjonalności ze standardowej biblioteki do kompilatora.

Zalety:

  • Lepsza diagnostyka: elementy wewnętrzne mogą być specjalnie zaprojektowane.
  • Lepsza wydajność: elementy wewnętrzne mogą być specjalnie zaprojektowane.

Niedogodności:

  • Zwiększona masa kompilatora: każdy specjalny przypadek komplikuje kompilator; złożoność zwiększa koszty utrzymania i prawdopodobieństwo błędów.
  • Wolniejsza iteracja: zmiana implementacji funkcjonalności wymaga zmiany samego kompilatora, co utrudnia utworzenie tylko małej biblioteki (poza std) do eksperymentowania.
  • Wyższy pasek wejścia: im droższe / trudniejsze jest coś zmienić, tym mniej ludzi może wskoczyć.

Oznacza to, że przeniesienie czegoś do kompilatora jest drogie , teraz iw przyszłości, a zatem wymaga solidnego uzasadnienia. W przypadku niektórych funkcji jest to konieczne (nie można ich zapisać jako zwykłego kodu), ale nawet wtedy opłaca się wyodrębnić minimalne i ogólne elementy, aby przejść do kompilatora i zbudować je na górze w standardowej bibliotece.

Matthieu M.
źródło
5

Jako projektant języka chciałbym powtórzyć niektóre inne odpowiedzi tutaj, ale podaj je oczami kogoś, kto buduje język.

Interfejs API nie jest gotowy, gdy skończysz dodawać do niego wszystko, co możesz. Interfejs API jest gotowy, gdy skończysz wyciągać z niego wszystko, co możesz.

Język programowania należy określić za pomocą jakiegoś języka. Musisz umieć przekazać znaczenie każdego programu napisanego w twoim języku. Ten język jest bardzo trudny do napisania, a jeszcze trudniejszy do dobrego pisania. Ogólnie rzecz biorąc, jest to bardzo precyzyjna i dobrze zorganizowana forma języka angielskiego używana do przekazywania znaczenia nie komputerowi, ale innym programistom, zwłaszcza tym, którzy piszą kompilatory lub tłumacze dla twojego języka. Oto przykład ze specyfikacji C ++ 11, [intro.multithread / 14]:

Widoczna sekwencja efektów ubocznych na obiekcie atomowym M, w odniesieniu do obliczenia wartości B M, jest maksymalną ciągłą podsekwencją efektów ubocznych w kolejności modyfikacji M, gdzie pierwszy efekt uboczny jest widoczny w odniesieniu do B , a dla każdego efektu ubocznego B nie dzieje się przed nim. Wartość obiektu atomowego M, ustalona na podstawie oceny B, będzie wartością zapisaną przez jakąś operację w widocznej sekwencji M względem B. [Uwaga: Można wykazać, że widoczna sekwencja efektów ubocznych wartości obliczenia są unikalne, biorąc pod uwagę poniższe wymagania dotyczące spójności. —Wskazówka]

Blek! Każdy, kto pogrążył się w zrozumieniu, w jaki sposób C ++ 11 obsługuje wielowątkowość, może docenić, dlaczego to sformułowanie musi być tak nieprzejrzyste, ale to nie wybacza faktu, że jest ... cóż ... tak nieprzejrzysty!

Porównaj to z definicją std::shared_ptr<T>::resetw sekcji biblioteki normy:

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

Efekty: równoważne zshared_ptr(p).swap(*this)

Jaka jest różnica? W części dotyczącej definicji języka autorzy nie mogą zakładać, że czytelnik rozumie prymitywy językowe. Wszystko musi być dokładnie określone w angielskiej prozie. Po przejściu do części dotyczącej definicji biblioteki możemy użyć języka do określenia zachowania. Często jest to o wiele łatwiejsze!

Zasadniczo można mieć płynną rozbudowę z prymitywów na początku dokumentu specyfikacji, aż do zdefiniowania, co uważamy za „standardowe funkcje biblioteki”, bez konieczności rysowania linii między „prymitywami językowymi” a funkcje „standardowej biblioteki”. W praktyce ta linia okazuje się niezwykle cenna do rysowania, ponieważ pozwala pisać niektóre z najbardziej skomplikowanych części języka (takie jak te, które muszą implementować algorytmy) przy użyciu języka zaprojektowanego do ich wyrażania.

I rzeczywiście widzimy pewne rozmyte linie:

  • W Javie java.lang.ref.Reference<T>mogą być podklasowane tylko przez standardowe klasy bibliotek, java.lang.ref.WeakReference<T> java.lang.ref.SoftReference<T>a java.lang.ref.PhantomReference<T>ich zachowanie Referencejest tak głęboko powiązane ze specyfikacją języka Java, że ​​musieli wprowadzić pewne ograniczenia w części tego procesu zaimplementowanej jako klasy „biblioteki standardowej”.
  • W języku C # istnieje klasa System.Delegate, która zawiera pojęcie delegatów. Mimo swojej nazwy nie jest delegatem. Jest to także klasa abstrakcyjna (nie można utworzyć instancji), z której nie można tworzyć klas pochodnych. Tylko system może to zrobić za pomocą funkcji zapisanych w specyfikacji języka.
Cort Ammon - Przywróć Monikę
źródło
2

Ma to stanowić uzupełnienie istniejących odpowiedzi (i jest zbyt długie, aby można było dodać komentarz).

Istnieją co najmniej dwa inne powody dla standardowej biblioteki:

Bariera wejścia

Jeśli dana funkcja językowa jest w funkcji biblioteki i chcę wiedzieć, jak to działa, mogę po prostu odczytać źródło tej funkcji. Jeśli chcę przesłać zgłoszenie błędu / prośbę o łatkę / ściągnięcie, kodowanie poprawki i przypadków testowych nie jest na ogół zbyt trudne. Jeśli jest w kompilatorze, muszę być w stanie zagłębić się w wewnętrzne elementy. Nawet jeśli jest w tym samym języku (i tak powinno być, każdy szanujący się kompilator powinien być hostem) kod kompilatora nie przypomina kodu aplikacji. Znalezienie odpowiednich plików może potrwać wieczność.

Odcinasz się od wielu potencjalnych współpracowników, jeśli pójdziesz tą drogą.

Ładowanie gorącego kodu

Wiele języków oferuje tę funkcję w takim czy innym stopniu, ale ogromnie skomplikowane byłoby przeładowanie na gorąco kodu wykonującego przeładowanie na gorąco. Jeśli SL jest oddzielny od środowiska wykonawczego, można go ponownie załadować.

Jared Smith
źródło
3
„każdy szanujący się kompilator powinien być hostowany” - wcale. Nie ma sensu mieć wersji powiedzmy LLVM napisanych w C, C ++, Objective-C, Swift, Fortran i tak dalej, aby skompilować wszystkie te języki.
gnasher729
@ gnasher729 nie jest specjalnym przypadkiem (wraz z innymi obiektami wielojęzycznymi, takimi jak CLR)?
Jared Smith
@JaredSmith Powiedziałbym, że jest to teraz ogólny przypadek, wcale nie wyjątkowy. Nikt już nie pisze „kompilatora” jako aplikacji monolitycznej. Zamiast tego produkują systemy kompilatorów . Większość funkcji kompletnego kompilatora jest całkowicie niezależna od konkretnego języka, który jest kompilowany, a większość części zależnej od języka można wykonać, podając różne dane określające gramatykę języka, a nie pisząc inny kod dla każdego języka chcę skompilować.
alephzero
2

To interesujące pytanie, ale jest już wiele dobrych odpowiedzi, więc nie podejmę się pełnego.

Jednak dwie rzeczy, które moim zdaniem nie przyciągnęły wystarczającej uwagi:

Po pierwsze, całość nie jest super wyraźna. To trochę spektrum właśnie dlatego, że istnieją powody, aby robić różne rzeczy. Na przykład kompilatory często wiedzą o standardowych bibliotekach i ich funkcjach. Przykład przykładu: funkcja „Hello World” C - printf - jest najlepsza, jaką mogę wymyślić. Jest to funkcja biblioteczna, jakoś musi być, ponieważ jest bardzo zależna od platformy. Ale jego zachowanie (zdefiniowane w implementacji) musi być znane kompilatorowi, aby ostrzec programistę przed złymi wywołaniami. Nie jest to szczególnie miłe, ale było postrzegane jako dobry kompromis. Nawiasem mówiąc, jest to prawdziwa odpowiedź na większość pytań „dlaczego ten projekt”: dużo kompromisu i „wydawało się wtedy dobrym pomysłem”. Nie zawsze „był to dobry sposób na zrobienie tego” lub „

Po drugie, pozwala standardowej bibliotece nie być tym standardem. Istnieje wiele sytuacji, w których język jest pożądany, ale standardowe biblioteki, które zwykle mu towarzyszą, nie są zarówno praktyczne, jak i pożądane. Najczęściej dzieje się tak w przypadku systemów programowania języków, takich jak C, na niestandardowych platformach. Na przykład, jeśli masz system bez systemu operacyjnego lub programu planującego: nie będziesz mieć wątków.

W przypadku standardowego modelu biblioteki (i obsługiwanego w nim wątkowania) można to obsłużyć czysto: kompilator jest prawie taki sam, można ponownie użyć bitów bibliotek, które mają zastosowanie, i wszystkiego, czego nie można usunąć. Jeśli zostanie to wstawione do kompilatora, sprawy zaczną się nieporządnie.

Na przykład:

  • Nie możesz być kompatybilnym kompilatorem.

  • Jak wskazałbyś swoje odchylenie od normy? Zauważ, że zwykle istnieje jakaś forma składni importu / dołączenia, która może nie działać, tj. Import pytonów lub dołączenie C, które łatwo wskazują na problem, jeśli brakuje czegoś w standardowym modelu biblioteki.

Podobne problemy mają również zastosowanie, jeśli chcesz ulepszyć lub rozszerzyć funkcjonalność „biblioteki”. Jest to o wiele bardziej powszechne, niż mogłoby się wydawać. Wystarczy trzymać się wątków: Windows, Linux i niektóre egzotyczne jednostki przetwarzające sieć robią wątki zupełnie inaczej. Podczas gdy bity linux / windows mogą być dość statyczne i być w stanie używać identycznego API, rzeczy NPU zmienią się z dniem tygodnia i API z nim. Kompilatory szybko się zmieniają, gdy ludzie decydują, które bity potrzebują do wsparcia / mogą zrobić bez dość szybko, jeśli nie ma sposobu na rozdzielenie tego rodzaju rzeczy.

drjpizzle
źródło