Spesso quando ci si approccia alla programmazione la nozione di linguaggio compilato e interpretato viene totalmente omessa e si passa dopo pochissimo tempo alla realizzazione del primo programma “Hello World”. Spesso ciò accade senza essere del tutto consapevoli delle meccaniche che, ad esempio, stanno dietro al nostro semplice print() in python.
Non tutti i linguaggi funzionano allo stesso modo, anzi, ogni linguaggio nasce per ovviare a carenze e mancanze presenti negli altri linguaggi esistenti. Eppure possiamo dividere i linguaggi di programmazione in due macrocategorie a seconda di come essi comunichino con il processore. Si parla quindi di linguaggi compilati e interpretati.
Rifacendoci all’esempio precedente la funzione print() di python risulta essere molto veloce in termini di programmazione, è necessario unicamente digitare il comando inserendo la scritta che vogliamo stampare all’interno delle parentesi.
Pensando al linguaggio C sorge spontaneo chiedersi perché fare più fatica dovendo includere la libreria, creare il main, scrivere la funzione (printf) e ricordarsi i “;” che terminano il comando.
Ovviamente i programmatori che utilizzano C non possono essere degli sconsiderati, nessuno si complicherebbe mai così tanto la vita.
Ebbene i motivi dietro a questa diversità li possiamo riscontrare nella natura stessa dei linguaggi, Python è un linguaggio interpretato e C è un linguaggio compilato.
Linguaggi compilati
La differenza tra i linguaggi compilati e i linguaggi interpretati è racchiusa nel modo in cui essi interagiscono con il computer. E’ nozione comune che i computer si esprimano e capiscano il codice binario, eppure sopra ho chiaramente parlato di funzioni scritte in lingua inglese (print). Ebbene in un linguaggio compilato queste funzioni, richiamate spesso da terminologia inglese, vengono convertite in Assembly attraverso il compilatore e successivamente assemblate in linguaggio binario in modo che il pc possa leggerle.
L’Assembly però è un codice che varia a seconda della famiglia dei processori risulta quindi molto dispendioso in termini di tempo ed energie scrivere un programma per ogni codice Assembly. La soluzione sta quindi nello scrivere un programma di alto livello che possa essere universale. Rimane però il problema che per effettuare delle modifiche si dovrà accedere al codice sorgente, cambiare il necessario e convertirlo nuovamente.
Il file così ottenuto però sarà un file binario che ad ogni lancio non avrà bisogno di essere convertito, vengono quindi separate le fasi di conversione e di lancio, e in assenza di modifiche la conversione verrà realizzata una sola volta indipendentemente da quante volte il programma verrà lanciato.
Una rappresentazione concreta di questa separazione possiamo individuarla in Ubuntu, dopo aver scritto il file lo si converte con il comando gcc FILE.c ottenendo un file binario di nome FILE. Una volta ottenuto questo file per lanciare il programma basterà scrivere ./FILE ogni volta che lo si vuole utilizzare, il programma non è quindi rappresentato dal codice sorgente ma dal FILE binario.
Linguaggi Interpretati
Per procedere con la spiegazione di questa seconda famiglia di linguaggi ci rifaremo all’etimologia stessa, Interpretati. Il processo di interpretazione consiste nella traduzione di un linguaggio in un altro linguaggio, in questo si tratta della traduzione dal linguaggio scelto in linguaggio binario in modo che il pc possa leggerlo ed eseguirlo.
La differenza con i linguaggi compilati sta nel fatto che il programma di un linguaggio compilato è rappresentato dal file già scritto in binario che una volta lanciato viene letto direttamente ed eseguito. Nei linguaggi interpretati il programma è rappresentato dal codice sorgente che ogni volta viene prima tradotto e poi compilato, con un conseguente calo di prestazioni. Eppure ciò permette una maggiore semplicità a livello di sintassi, come mostrato all’inizio con python, ma soprattutto permette al programma di girare in ogni macchina con ogni sistema operativo.
Linguaggi compilati e interpretati: i linguaggi pseudocompilati
Alcuni linguaggi, come Java, vengono compilati in un linguaggio intermedio come, in questo caso, il Bytecode che poi grazie alla Java Virtual Machine viene interpretato in istruzioni per il processore. Ciò permette di aver file leggeri, il Bytecode genera file di piccole dimensioni, ma permette anche di far girare il programma su ogni macchina grazie all’intervento di un sistema di interpretazione che non dipende dalla macchina.
Differenze, Vantaggi e Svantaggi tra linguaggi di programmazione interpretati e compilati
Linguaggi Compilati |
Linguaggi Interpretati |
Un linguaggio compilato genera un file binario non modificabile |
Un linguaggio interpretato è scritto in un linguaggio di programmazione definito e modificabile in ogni momento |
Le istruzioni vengono inviate direttamente al processore |
Le istruzioni necessitano di una traduzione prima di arrivare al processore |
Per eseguire il programma dal codice sorgente si necessitano due step separati |
Il codice sorgente viene eseguito attraverso un unico comando |
Essendo il programma già tradotto l’esecuzione risulta essere più veloce |
Il programma deve essere tradotto ogni volta aumentando i tempi di esecuzione |
Il programma può essere eseguito solo in determinate macchine e sistemi operativi |
Il programma funziona su ogni macchina e sistema |
Gli errori di compilazione impediscono al codice di essere compilato |
Gli errori di compilazione sono visibili solo se il programma viene lanciato |
Esempi di linguaggi Compilati sono C, C++, Delphi… |
Esempi di linguaggi Interpretati sono Python, Javascript, Perl, PHP… |
Al momento esistono molti linguaggi, alcuni più facili da imparare, altri più difficili, alcuni più veloci e altri più lenti, ma l’abilità di un programmatore sta nell’utilizzare il linguaggio giusto per il giusto progetto. Ogni linguaggio ha il suo motivo di esistere e possiede della caratteristiche che lo rendono unico, l’unica cosa da fare è studiare, imparare, e migliorare sempre di più.