Digitale computers begrijpen niet de talen die mensen spreken. In plaats daarvan gebruiken ze een binaire taal die machinecode of machinetaal wordt genoemd. Machinecode bestaat uit een reeks eenvoudige computerinstructies waarbij elke instructie wordt uitgedrukt als een reeks binaire cijfers of bits (d.w.z. 1’s en 0’s). Verschillende computers “spreken” of “begrijpen” gewoonlijk verschillende machinetalen. Zo kan de ene computer de ADD-bewerking weergeven als 10011111
, terwijl een andere dezelfde bewerking weergeeft als 000110
. Niet alleen de bitpatronen verschillen van computer tot computer, maar zelfs het aantal bits dat wordt gebruikt om een bewerking weer te geven, kan verschillen.
Wanneer een programma wordt uitgevoerd, fungeert het besturingssysteem (b.v. Windows, Linux, OS X, enz.) als een gastheeromgeving die diensten verleent aan het programma. Deze diensten omvatten essentiële ondersteuning, zoals toegang tot het toetsenbord, het scherm en de harde schijven. Helaas verschilt ook de manier waarop het programma toegang krijgt tot deze diensten van besturingssysteem tot besturingssysteem. Als gevolg van de verschillen tussen machinetalen en besturingssysteemvereisten zijn programma’s die in machinetaal zijn geschreven meer gericht op het systeem waarop het programma draait dan op de manier waarop het programma een probleem oplost. Bovendien betekent dit ook dat het niet mogelijk is machinecode tussen verschillende computers te verplaatsen zonder een of andere vertaalservice te bieden – meestal in de vorm van een virtuele machine.
Het schrijven van programma’s in machinetaal is traag, vervelend en foutgevoelig. De oplossing was het ontwikkelen van programmeertalen op een hoger niveau, die meer gericht waren op het probleem en minder op het systeem (de hardware en het besturingssysteem) waarop het programma werd uitgevoerd (zie figuur 2). Maar computers voeren gewoonlijk geen programma’s uit die in hogere talen zijn geschreven, dus moet er een manier zijn om een programma dat in een hogere taal is geschreven naar machinetaal te vertalen. Twee soorten computerprogramma’s voeren de noodzakelijke vertaling uit: compilers en interpreters.
Een compiler is een programma dat andere programma’s die zijn geschreven in een programmeertaal op hoog niveau, zoals C of C++, vertaalt in machinecode of machinetaal.Andere talen, zoals Java en C#, nemen een andere route: Programma’s die in deze talen zijn geschreven, worden gecompileerd naar een tussenliggende representatie (een representatie die ergens tussen de high-level taal en machinetaal in ligt) die vaak virtuele machinecode wordt genoemd. De virtuele machinecode wordt dan input voor een ander programma, een interpreter of virtuele machine (VM, een programma dat een hardware CPU simuleert). Sommige talen, zoals Javascript en Perl, zijn volledig geïnterpreteerd, dat wil zeggen dat ze niet worden gecompileerd maar direct worden geïnterpreteerd.
Elke benadering van het uitvoeren van een programma dat is geschreven in een programmeertaal op hoog niveau heeft voor- en nadelen. Programma’s die zijn geschreven in volledig gecompileerde talen (bijv. C en C++) worden sneller uitgevoerd dan programma’s die zijn geschreven in gedeeltelijk gecompileerde talen (bijv. Java en C#) en worden veel sneller uitgevoerd dan programma’s die zijn geschreven in volledig geïnterpreteerde talen (bijv. Javascript en Perl). Om een idee te geven van het verschil in prestaties, laten we zeggen dat een C++ programma, eenmaal gecompileerd, wordt uitgevoerd in tijd 1.0. Een equivalent programma, geschreven in een taal die wordt gecompileerd en vervolgens geïnterpreteerd, zal over het algemeen in tijd 3 tot 10 worden uitgevoerd. Hetzelfde programma uitgevoerd in een zuiver geïnterpreteerde taal zal in een tijd van ongeveer 100 lopen. Hedendaagse implementaties van de Java en C# VM’s maken gebruik van een just in time (JIT) interpreter die een deel van de virtuele code compileert naar machinecode terwijl deze wordt verwerkt. JIT-processoren reduceren de runtime tot ongeveer 1,5 maal die van zuiver gecompileerde taalsystemen. De programmeertaal Python is een beetje anders: het grootste deel van een Python-programma wordt geïnterpreteerd, maar is relatief klein en heeft dus een minimale impact op de totale runtime. De meeste Python bibliotheken, waar het programma de meeste tijd doorbrengt, zijn in C geschreven, zodat Python programma’s bijna net zo snel lopen als een equivalent C programma.
Aan de andere kant kunnen de uitvoerbare programma’s die door een pure compiler worden geproduceerd niet tussen verschillende platforms worden overgezet (je kunt bijvoorbeeld geen Windows programma op een Apple computer draaien), terwijl programma’s die in geïnterpreteerde talen zijn geschreven gemakkelijker tussen verschillende computers kunnen worden overgezet. Deze overdraagbaarheid wordt bereikt door voor elk platform (combinatie van hardware en besturingssysteem) een VM of interpreter aan te bieden. Interpreters en VM’s zijn programma’s die zijn geschreven in zuiver gecompileerde talen, dus ze zijn niet overdraagbaar, maar de programma’s die ze verwerken zijn dat wel.