Het verschil tussen een compiler en een interpreter
On december 31, 2021 by adminAfgaande op hun definities lijkt het verschil tussen een compiler en een interpreter duidelijk genoeg:
- interpreter is een programma dat rechtstreeks instructies uitvoert die in een programmeertaal zijn geschreven
- compiler is een programma dat broncode omzet in een taal op laag(er)niveau
Als je echter dieper graaft, vind je enige vervaging tussen de twee.
In feite zou een interpreter de brontaal kunnen vertalen in een tussenvorm, om de uitvoering te versnellen. Dat is wat gewoonlijk gebeurt met een taal die op een virtuele machine is gebaseerd. Dit leidt natuurlijk tot de volgende vragen:
Zijn alle talen die gebruik maken van een virtuele machine geïnterpreteerd?
Zijn ze eigenlijk allemaal gecompileerd?
Je zou kunnen zeggen beide: een taal wordt eerst gecompileerd in een tussenvorm/taal en vervolgens wordt dit tussenliggende ding geïnterpreteerd op runtime. Dat leidt ook tot een andere kwestie, een compiler en een interpreter moet je niet zien als één programma, maar meer als een groep programma’s, een systeem. Wat u, als gebruiker, ziet als een compiler kan in feite meer dan één programma omvatten. Het kan bijvoorbeeld ook een linker omvatten: een programma dat verschillende objectbestanden samenvoegt in één bestand, zodat het gemakkelijker kan worden gebruikt. Iets soortgelijks kan worden gezegd van een interpreter.
Can You Tell Me Everything About Compilers & Interpreters?
Wat zijn dus alle onderdelen waaruit een compiler of een interpreter is opgebouwd? Een nauwkeurig en technisch antwoord op dergelijke vragen zou je in de academische wereld kunnen zoeken. Of je kunt discussies over deze onderwerpen vinden op StackOverflow.
Waar het ons als ontwikkelaars, of zelfs ons als makers van een taal, werkelijk om gaat, is wat de verschillen zijn in het werken met beide. Beide hebben voor- en nadelen, en in feite kunnen sommige talen zowel een interpreter als een compiler hebben, of meer dan een. Dat is wat we gaan zien.
Het belangrijkste punt staat nog steeds: een interpreter voert de code nu uit, een compiler bereidt de broncode voor op een uitvoering die later komt. Alle praktische verschillen vloeien voort uit deze verschillende doelstellingen.
Hoe distribueer je een programma
In praktische zin is een belangrijk verschil dat een compiler een op zichzelf staand programma genereert, terwijl een geïnterpreteerd programma altijd de interpreter nodig heeft om te kunnen draaien.
Als je eenmaal een gecompileerd programma hebt, kun je het uitvoeren zonder dat je nog iets anders hoeft te installeren. Dit vereenvoudigt de distributie. Aan de andere kant werkt het uitvoerbare programma op één specifiek platform: verschillende besturingssystemen en verschillende processors hebben verschillende gecompileerde versies nodig. Een gecompileerd C++ programma zou bijvoorbeeld kunnen werken op een computer met een x86 processor, maar niet op een met een ARM chip. Of het zou kunnen werken op een Linux systeem, maar niet op een Windows.
Als u een programma gaat interpreteren kunt u dezelfde kopie distribueren naar gebruikers op verschillende platforms. Zij hebben dan echter wel een interpreter nodig die op hun specifieke platform draait. Je kunt ofwel de originele broncode distribueren of een tussenvorm. Een intuïtieve manier om naar een interpreter te kijken is deze: het is als de eval
functie in JavaScript. Het werkt overal waar JavaScript werkt, maar het heeft een JavaScript interpreter voor dat platform nodig om te kunnen draaien.
Cross-Platform Support
Dit is een technisch verschil dat leidt tot belangrijke werkelijke gevolgen: het is gemakkelijker om cross-platform programma’s te maken met een geïnterpreteerde programmeertaal.
Dat komt omdat, voor het grootste deel, je gewoon een programma maakt voor het interpreter platform. Het is de interpreter zelf die het zal vertalen in de juiste vorm voor het echte platform (b.v. Windows/Linux en x86/ARM). Natuurlijk zijn er nog enkele verschillen in elk platform waarvan je je bewust moet zijn. Een veel voorkomend voorbeeld is het directory scheidingsteken.
Wanneer je daarentegen een programma compileert, moet je zelf zorg dragen voor al die kleine verschillen tussen elk platform. Dit gebeurt gedeeltelijk omdat gecompileerde talen meestal van een laag(er) niveau zijn, zoals C++, en je dus minder toegang hebt tot het systeem en dus meer verantwoordelijkheid. Maar een andere reden is dat alle bibliotheken die je gebruikt zelf verschillende platformen moeten ondersteunen. Dus, als ze Windows niet ondersteunen, kun jij Windows niet ondersteunen.
Snelheid heeft meerdere gezichten
Opnieuw, in het geval van snelheid, hebben we een soort paradox: een compiler is zowel sneller als langzamer dan een interpreter. Veel mensen weten dat een gecompileerd programma veel sneller is dan een geïnterpreteerd programma, maar dit is niet het hele plaatje. Een gecompileerd programma wordt sneller uitgevoerd dan een geïnterpreteerd programma, maar het kost meer tijd om een programma te compileren en uit te voeren dan om het alleen maar te interpreteren.
Een compiler produceert inderdaad snellere programma’s. Dat komt doordat hij elke instructie maar één keer hoeft te analyseren, terwijl een interpreter die elke keer moet analyseren. Bovendien kan een compiler de uitvoerbare code die hij produceert, optimaliseren. Dat komt zowel omdat hij precies weet waar hij zal lopen als omdat het tijd kost om de code te optimaliseren. Tijd die de interpretatie te traag zou maken.
Runtime Snelheid Versus Ontwikkelingssnelheid
Je zou kunnen denken dat dit muggenzifterij is: als je een programma compileert loopt het sneller, de tijd die het kost om te compileren doet er niet toe. Dit is meestal de oude school opvatting. En zonder twijfel wordt het resulterende programma meer keren uitgevoerd dan het gecompileerd is. Dus wat maakt het uit of de ontwikkeling meer tijd kost? Wel, het vergt zeker een “breng de pijn” houding ten opzichte van ontwikkeling die enigszins bewonderenswaardig is. Maar wat als de tijdwinst niet relevant is, terwijl het verlies in ontwikkelproductiviteit aanzienlijk is?
Het is één ding als je een besturingssysteem maakt en iets anders als je een selfie app maakt. Zelfs je gebruikers geven misschien de voorkeur aan een niet eens merkbaar verlies in runtime snelheid in ruil voor snellere functies. Er is geen een-size-fits-all antwoord: in sommige contexten productiviteit belangrijker dan snelheid, in andere is het omgekeerde waar.
The Mysteries Of Debugging
Er is een ander bijzonder aspect dat uiteindelijk meer onzeker dan wat men zou aspect: debugging. Op papier is debuggen gemakkelijker bij gebruik van een interpreter dan bij gebruik van een compiler. Dat is waar om verschillende redenen:
- met de interpreter is er één versie van de executable; je hebt geen debug-versie nodig voor ontwikkeling en een release-versie voor de eindgebruiker
- er zijn minder platform-specifieke bugs bij gebruik van een interpreter
- sinds de interpreter code on the fly transformeert, is de informatie van de broncode nog steeds beschikbaar
- since the interpreter executes one statement at a time, it is easier to find a mistake
The Difference that Development Tools Makes
Whilst this all is true in practice, this might be less relevant than it seems. In feite, als je nadenkt over je ervaring, zou je waarschijnlijk vinden dat het debuggen van JavaScript moeilijker is dan het debuggen van C++. Waarom is dat? Voor een deel is dat het ontwerp van de talen zelf. JavaScript gebruikt dynamische typing, terwijl C++ statische typing gebruikt. Dat laatste maakt het makkelijker om fouten vroegtijdig op te sporen. Maar uiteindelijk komt het neer op het ontwikkelgereedschap. C++ met de hand compileren is moeilijk, dus de meeste mensen gebruiken IDE’s om ermee te ontwikkelen. Aan de andere kant kunt u gemakkelijk gebruik maken van tekst editor en command line tools om te ontwikkelen in JavaScript.
Dit betekent dat, in praktische termen, als u ontwikkelt met C++, u ook C++ kunt debuggen. In plaats daarvan kun je ontwikkelen met JavaScript zonder te weten hoe je goed moet debuggen in JavaScript.
Dit gezegd hebbende, als we ze in dezelfde context plaatsen, elk met een geweldige IDE en ondersteunende tools, komt de situatie weer terug bij normaal. Inderdaad veel geïnterpreteerde omgeving worden gebruikt door mensen die willen leren hoe een nieuwe taal te gebruiken. Het is gemakkelijker te testen, en te vinden wat goed en fout is, door te kijken naar wat er regel voor regel en in real time gebeurt.
Samenvatting
We hebben de belangrijkste verschillen gezien die van belang zijn tussen een compiler en een interpreter. Belangrijker nog is dat we hebben gezien dat de gevolgen van verschillende filosofieën belangrijker zijn dan de technische. Kortom, er zijn culturen die samengaan met bepaalde technische keuzes die uiteindelijk op zichzelf relevant blijken te zijn. Als je snelheid en ontwikkelgemak wilt, ga je alle technologieën voor snelheid kiezen en niet slechts één. En je gebruikers gaan je volgen.
Dit is een cruciaal aspect om over na te denken, vooral als je je eigen programmeertaal wilt maken. Rasmus Lerdorf creëerde PHP om makkelijk in gebruik te zijn. En inderdaad was het ongelooflijk eenvoudig te gebruiken in vergelijking met de alternatieven, althans op het moment van zijn creatie. Maar het begon meer als een bibliotheek dan als een taal. En hoewel het veel verbeterd is, lijdt het nog steeds onder zijn begin. Je kunt nog steeds goede PHP code maken, maar minder van zijn gebruikers dan gewoonlijk doen dat. Want als je gewoon iets nodig hebt dat werkt, beveiliging, onderhoud, etc., dan komt al de rest later.
Als je wilt weten hoe je praktisch een interpreter of een compiler voor je taal kunt bouwen, dan kun je misschien eens kijken naar de bronnen om een programmeertaal te maken. Als je dat wilt leren, en alles wat je nodig hebt om je eigen taal te maken, hoef je alleen maar een geweldig boek uit te zoeken, geliefd bij zowel kinderen als volwassenen, over hoe je pragmatische, lichtgewicht talen kunt maken.
5 dingen om goed te doen bij het bouwen van een taal
Ontvang de checklist per e-mail en krijg meer tips over het bouwen van talen
Geef een antwoord