The Difference Between a Compiler and an Interpreter
On 31 grudnia, 2021 by adminZgodnie z ich definicjami, różnica między kompilatorem a interpreterem wydaje się wystarczająco jasna:
- interpreter to program, który bezpośrednio wykonuje instrukcje napisane w języku programowania
- kompilator to program, który przekształca kod źródłowy w języku niskiego(er)poziomu
Jeśli jednak pokopiesz głębiej, znajdziesz pewne rozmycie między nimi.
W rzeczywistości interpreter mógłby przetłumaczyć język źródłowy w formie pośredniej, aby przyspieszyć wykonanie. To jest to, co zwykle dzieje się z językiem, który opiera się na maszynie wirtualnej. To naturalnie prowadzi do kilku pytań:
Czy wszystkie języki, które używają maszyny wirtualnej są interpretowane?
Czy wszystkie są faktycznie kompilowane?
Można powiedzieć, że oba: język jest najpierw kompilowany w pośredniej formie / języku, a następnie ta pośrednia rzecz jest interpretowana w czasie wykonywania. Co również prowadzi do innej kwestii, kompilator i interpreter nie powinny być uważane za jeden program, ale bardziej za grupę programów, system. To, co ty, jako użytkownik, myślisz jako kompilator, może w rzeczywistości zawierać więcej niż jeden program. Na przykład, może zawierać linker: program, który łączy różne pliki obiektowe w jeden plik, aby można go było łatwiej używać. Coś podobnego można powiedzieć o interpreterze.
Can You Tell Me Everything About Compilers & Interpreters?
Więc, jakie są wszystkie kawałki, które składają się na kompilator lub interpreter? Możesz szukać precyzyjnej i technicznej odpowiedzi na takie pytania w środowisku akademickim. Możesz też znaleźć dyskusje na ten temat na StackOverflow.
To, co naprawdę ma znaczenie dla nas jako programistów, lub nawet dla nas jako twórców języka, to jakie są różnice w pracy z nimi. Oba mają zalety i wady, a w rzeczywistości niektóre języki mogą mieć zarówno interpreter, jak i kompilator, lub więcej niż jeden. To jest to, co zobaczymy.
Główny punkt nadal pozostaje: interpreter wykonuje kod teraz, kompilator przygotowuje kod źródłowy do wykonania, które nadejdzie później. Wszystkie praktyczne różnice wynikają z tych różnych celów.
Jak rozpowszechniać program
W praktyce jedną ważną różnicą jest to, że kompilator generuje samodzielny program, podczas gdy interpretowany program zawsze potrzebuje interpretera do uruchomienia.
Gdy masz skompilowany program, możesz go uruchomić bez potrzeby instalowania czegokolwiek innego. To upraszcza dystrybucję. Z drugiej strony, program wykonywalny działa na jednej konkretnej platformie: różne systemy operacyjne i różne procesory potrzebują różnych skompilowanych wersji. Na przykład, skompilowany program w C++ może działać na komputerze z procesorem x86, ale nie na takim z układem ARM. Albo może działać w systemie Linux, ale nie w Windows.
Jeśli zamierzasz interpretować program, możesz rozprowadzać tę samą kopię do użytkowników na różnych platformach. Jednak będą oni potrzebowali interpretera, który działa na ich konkretnej platformie. Możesz albo rozprowadzać oryginalny kod źródłowy, albo formę pośrednią. Intuicyjny sposób patrzenia na interpreter jest następujący: jest on jak funkcja eval
w JavaScript. Działa wszędzie tam gdzie działa JavaScript, ale potrzebuje interpretera JavaScript dla tej platformy aby działać.
Wsparcie międzyplatformowe
To jest techniczna różnica, która prowadzi do ważnych rzeczywistych konsekwencji: łatwiej jest tworzyć programy międzyplatformowe z interpretowanym językiem programowania.
To dlatego, że, w większości, po prostu tworzysz program dla platformy interpretera. To sam interpreter przetłumaczy go na właściwą formę dla prawdziwej platformy (np. Windows/Linux i x86/ARM). Oczywiście nadal istnieją pewne różnice w każdej platformie, o których musisz wiedzieć. Typowym przykładem jest znak separatora katalogów.
Gdy kompilujesz program, musisz sam zadbać o wszystkie małe różnice pomiędzy każdą platformą. Dzieje się tak po części dlatego, że języki kompilowane są zwykle językami niskiego poziomu, takimi jak C++, więc dają ci mniejszy dostęp do systemu, a tym samym większą odpowiedzialność. Innym powodem jest to, że wszystkie biblioteki, których używasz, muszą obsługiwać różne platformy. Więc, jeśli nie obsługują Windows, nie możesz obsługiwać Windows.
Speed Has Multiple Faces
Ponownie, w przypadku prędkości, mamy pewien paradoks: kompilator jest zarówno szybszy jak i wolniejszy niż interpreter. Wiele osób wie, że skompilowany program jest znacznie szybszy niż interpretowany, ale to nie jest cały obraz. Skompilowany program jest szybszy do uruchomienia niż zinterpretowany, ale kompilacja i uruchomienie programu zajmuje więcej czasu niż jego interpretacja.
Kompilator rzeczywiście produkuje szybsze programy. Dzieje się tak zasadniczo dlatego, że musi analizować każde oświadczenie tylko raz, podczas gdy interpreter musi analizować je za każdym razem. Co więcej, kompilator może zoptymalizować kod wykonywalny, który produkuje. Dzieje się tak zarówno dlatego, że wie dokładnie, gdzie zostanie uruchomiony, jak i dlatego, że optymalizacja kodu zajmuje czas. Czas, który sprawiłby, że interpretacja byłaby zbyt wolna.
Runtime Speed Versus Development Speed
Możesz pomyśleć, że to jest nitpicking: jeśli skompilujesz program to działa szybciej, czas, który zajmuje kompilacja nie ma znaczenia. To jest zazwyczaj opinia starej szkoły. I bez wątpienia program wynikowy jest uruchamiany więcej razy niż jest kompilowany. Kogo więc obchodzi, że tworzenie programu zajmuje więcej czasu? Cóż, na pewno wymaga to postawy „przynieś ból” do rozwoju, która jest godna podziwu. Ale co jeśli zyski w czasie działania nie są istotne, podczas gdy straty w produktywności rozwoju są znaczące?
Jedną rzeczą jest, jeśli tworzysz system operacyjny, a inną, jeśli robisz aplikację do selfie. Nawet twoi użytkownicy mogą preferować niezauważalną stratę w szybkości działania w zamian za szybsze uzyskanie funkcji. Nie ma jednej uniwersalnej odpowiedzi: w niektórych kontekstach produktywność liczy się bardziej niż szybkość, w innych jest odwrotnie.
The Mysteries Of Debugging
Jest jeszcze jeden szczególny aspekt, który kończy się bardziej niepewny niż to, co można by było przewidzieć: debugowanie. Na papierze debugowanie jest łatwiejsze przy użyciu interpretera niż przy użyciu kompilatora. Jest to prawdą z kilku powodów:
- z interpreterem jest jedna wersja pliku wykonywalnego; nie potrzebujesz wersji debugowania dla rozwoju i wersji wydania dla użytkownika końcowego
- jest mniej błędów specyficznych dla platformy przy użyciu interpretera
- ponieważ interpreter przekształca kod w locie, informacje z kodu źródłowego są nadal dostępne
- ponieważ interpreter wykonuje jedną instrukcję na raz, łatwiej jest znaleźć błąd
Różnica, jaką robią narzędzia programistyczne
Choć to wszystko jest prawdą w praktyce, może to być mniej istotne niż się wydaje. W rzeczywistości, jeśli pomyślisz o swoim doświadczeniu, prawdopodobnie stwierdzisz, że debugowanie JavaScript jest trudniejsze niż debugowanie C++. Dlaczego tak jest? Po części wynika to z konstrukcji samych języków. JavaScript używa dynamicznego typowania, podczas gdy C++ używa statycznego typowania. To ostatnie ułatwia wczesne wyłapywanie błędów. Ale w końcu wszystko sprowadza się do narzędzi programistycznych. Ręczna kompilacja C++ jest trudna, więc większość ludzi używa IDE, by z nim pracować. Z drugiej strony, można łatwo użyć edytora tekstu i narzędzi wiersza poleceń, aby rozwijać się w JavaScript.
To oznacza, że w praktyce, jeśli rozwijasz się w C++, możesz również debugować C++. Zamiast tego możesz rozwijać się w JavaScript nie wiedząc jak poprawnie debugować w JavaScript.
Powiedziawszy to, jeśli umieścimy je w tym samym kontekście, każdy z nich z doskonałym IDE i narzędziami wspierającymi, sytuacja wraca do normy. Rzeczywiście wiele interpretowanych środowisk jest używanych przez ludzi, którzy chcą się nauczyć, jak używać nowego języka. Łatwiej jest testować i znaleźć co jest dobre a co złe, patrząc na to co się dzieje linia po linii i w czasie rzeczywistym.
Podsumowanie
Widzieliśmy główne różnice, które mają znaczenie między kompilatorem a interpreterem. Co ważniejsze, widzieliśmy, że konsekwencje różnych filozofii są ważniejsze niż te techniczne. W skrócie, są kultury, które przychodzą z pewnymi technicznymi wyborami, które kończą się być istotne same w sobie. Jeśli chcesz szybkość i łatwość rozwoju, masz zamiar wybrać wszystkie technologie dla szybkości, a nie tylko jeden. A twoi użytkownicy będą podążać za tobą.
Jest to kluczowy aspekt do przemyślenia, szczególnie jeśli chcesz stworzyć swój własny język programowania. Rasmus Lerdorf stworzył PHP, aby był łatwy w użyciu. I rzeczywiście, był on niewiarygodnie łatwy w użyciu w porównaniu do innych języków, przynajmniej w czasie jego tworzenia. Ale zaczynał bardziej jako biblioteka niż jako język. I choć bardzo się poprawił, wciąż cierpi z powodu swoich początków. Nadal możesz tworzyć dobry kod PHP, ale robi to mniej jego użytkowników niż zwykle. Bo jeśli potrzebujesz tylko czegoś, co działa, bezpieczeństwa, konserwacji, itd., cała reszta przychodzi później.
Jeśli chcesz wiedzieć, jak możesz praktycznie zbudować interpreter lub kompilator dla swojego języka, możesz chcieć rzucić okiem na zasoby do tworzenia języka programowania. Jeśli chcesz się tego nauczyć, a także wszystkiego, czego potrzebujesz, aby stworzyć swój własny język, wystarczy, że wybierzesz świetną książkę, uwielbianą zarówno przez dzieci, jak i dorosłych, o tym, jak tworzyć pragmatyczne, lekkie języki.
5 rzeczy, które należy uwzględnić przy tworzeniu języka
Otrzymaj listę kontrolną pocztą elektroniczną i uzyskaj więcej wskazówek na temat tworzenia języków
.
Dodaj komentarz