I computer digitali non capiscono le lingue che parlano gli umani. Il codice macchina consiste in una sequenza di semplici istruzioni per computer con ogni istruzione espressa come una stringa di cifre binarie o bit (cioè, 1 e 0). Diversi computer tipicamente “parlano” o “capiscono” diversi linguaggi macchina. Per esempio un computer può rappresentare l’operazione ADD come 10011111
mentre un altro potrebbe rappresentare le stesse operazioni come 000110
. Non solo i modelli di bit sono tipicamente diversi da un tipo di computer all’altro, ma anche il numero di bit usati per rappresentare un’operazione può essere diverso.
Inoltre, quando un programma viene eseguito, il sistema operativo (ad esempio Windows, Linux, OS X, ecc.) agisce come un ambiente host che fornisce servizi al programma. Sfortunatamente, come il programma accede a questi servizi è anche diverso da un sistema operativo all’altro. Come risultato delle differenze tra i linguaggi macchina e i requisiti del sistema operativo, i programmi scritti in linguaggio macchina sono più focalizzati sul sistema che esegue il programma che su come il programma risolve un problema. Inoltre, significa anche che non è possibile spostare il codice macchina tra diversi computer senza fornire qualche tipo di servizio di traduzione – di solito sotto forma di una macchina virtuale.
Scrivere programmi in linguaggio macchina è lento, noioso e soggetto a errori. La soluzione è stata quella di sviluppare linguaggi di programmazione di livello superiore che si concentrano di più sul problema e meno sul sistema (l’hardware e il sistema operativo) che esegue il programma (vedi Figura 2). Ma i computer in genere non eseguono programmi scritti in linguaggi di alto livello, quindi ci deve essere un modo per tradurre un programma scritto in un linguaggio di alto livello in linguaggio macchina. Due tipi di programmi per computer eseguono la traduzione necessaria: compilatori e interpreti.
Un compilatore è un programma che traduce altri programmi scritti in un linguaggio di programmazione di alto livello come C o C++ in codice macchina o linguaggio macchina.Altri linguaggi come Java e C# prendono una strada diversa: I programmi scritti in questi linguaggi sono compilati in una rappresentazione intermedia (una rappresentazione che sta da qualche parte tra il linguaggio di alto livello e il linguaggio macchina) che è spesso chiamata codice macchina virtuale. Il codice della macchina virtuale diventa poi un input per un altro programma chiamato interprete o macchina virtuale (VM, un programma che simula una CPU hardware). Alcuni linguaggi, come Javascript e Perl, sono completamente interpretati, cioè non vengono compilati ma interpretati direttamente.
Ogni approccio per eseguire un programma scritto in un linguaggio di programmazione di alto livello ha vantaggi e svantaggi. I programmi scritti in linguaggi completamente compilati (ad esempio, C e C++) vengono eseguiti più velocemente dei programmi scritti in linguaggi parzialmente compilati (ad esempio, Java e C#) ed eseguiti molto più velocemente dei programmi scritti in linguaggi completamente interpretati (ad esempio, Javascript e Perl). Per dare un’idea della differenza di prestazioni, diciamo che un programma C++, una volta compilato, viene eseguito nel tempo 1.0. Un programma equivalente scritto in un linguaggio compilato e poi interpretato viene generalmente eseguito in un tempo da 3 a 10. Lo stesso programma eseguito in un linguaggio puramente interpretato verrà eseguito in un tempo di circa 100. Le implementazioni contemporanee delle VM di Java e C# usano un interprete just in time (JIT) che compila parte del codice virtuale in codice macchina mentre lo elabora. Gli interpreti JIT riducono il tempo di esecuzione a circa 1,5 volte quello dei sistemi in linguaggio puramente compilato. Il linguaggio di programmazione Python è un po’ diverso: la parte principale di un programma Python è interpretata ma è relativamente piccola e quindi ha un impatto minimo sul tempo di esecuzione complessivo. La maggior parte delle librerie Python, dove il programma passa la maggior parte del suo tempo, sono scritte in C, quindi i programmi Python girano quasi altrettanto velocemente di un programma C equivalente.
D’altra parte, i programmi eseguibili prodotti da un compilatore puro non possono essere trasferiti tra piattaforme diverse (ad esempio, non è possibile eseguire un programma Windows su un computer Apple), mentre i programmi scritti in linguaggi interpretati sono più facilmente trasferibili tra computer diversi. Questa portabilità si ottiene fornendo una VM o un interprete per ogni piattaforma (combinazione di hardware e sistema operativo). Gli interpreti e le VM sono programmi scritti in linguaggi puramente compilati, quindi non sono portabili, ma i programmi che elaborano sì.