Build time e Linguaggi di programmazione
Come abbiamo visto nella lezione sui paradigmi di programmazione, il linguaggio di programmazione è progettato in base ad un certo paradigma: ad esempio Fortran è basato su programmazione procedurale, Pascal su quella strutturata, Smalltalk su quella ad oggetti, ed Haskell su quella funzionale. Esistono poi numerosi linguaggi multiparadigma: C++ o Python ne sono un esempio.
Tuttavia un linguaggio di programmazione non è solo una entità logico-matematica, con una grammatica e delle strutture dati. Esso, in altri termini, non è solo una entità con cui si ha a che fare solo a compile time, ma deve essere trasformabile in codice eseguibile a build time, come abbiamo visto nella lezione sul ciclo di sviluppo.
In questa lezione approfondiremo quindi il processo di build time dal punto di vista tecnologico, e successivamente analizzeremo le varie famiglie di linguaggi da un punto di vista delle loro applicazioni, tenendo conto sia del paradigma di programmazione, sia del tipo di build che essi generano.
Build time
A build time il linguaggio viene trasformato in qualcosa di eseguibile. Esistono due tecniche principali, la compilazione e l’interpretazione, con un insieme di metodologie per prendere il meglio dei due mondi.
Compilazione
Nella compilazione il codice dell’applicazione (detto codice sorgente) viene analizzato da un software detto compilatore che lo traduce in istruzioni e simboli di codice binario eseguibile. La compilazione viene effettuata una volta soltanto e produce un file detto oggetto. Se sono presenti errori, il compilatore li rileva e li segnala al programmatore, interrompendo l’operazione. Il compilatore quindi effettua una validazione del codice sorgente.
Il compilatore deve essere specifico per l’architettura hardware dove verrà eseguito il codice. Quindi lo stesso programma dovrà essere compilato separatamente per ogni piattaforma (es. Windows, Linux, ecc.).
Il codice oggetto però non è sufficiente. Per essere eseguito un programma ha bisogno di utilizzare un insieme di librerie esterne per accedere a determinate risorse (ad esempio per scrivere su file, per accedere alla rete, ecc.), librerie che a compile time sono indicate dal programmatore ma che poi è necessario includere nell’applicativo finale. E’ prevista quindi una operazione chiamata linking, che consiste nel creare un pacchetto contenente sia il codice oggetto che le librerie. Il risultato viene chiamato build, ed assume la forma di una applicazione eseguibile (un file .exe, una app mobile, un eseguibile per server, ecc.).

I compilatori odierni sono estremamente efficienti e riescono ad ottenere codice macchina che ha prestazioni quasi identiche a quelle che si avrebbero con un programma scritto direttamente in assembly. Ad esempio i linguaggi come C, C++ e Swift sono compilati.
Interpretazione
L’interpretazione è una modalità alternativa per cui il programma non viene compilato ma viene eseguito. Nei linguaggi interpretati è presente un software, detto runtime, che crea un ambiente di esecuzione per il programma e al suo interno prevede un interprete che legge il codice una riga alla volta e lo esegue nel runtime, memorizzando le variabili, eseguendo le operazioni di input/output, ecc. Se sono presenti errori, l’esecuzione si interrompe e viene segnalato l’errore all’utente (alcuni interpreti fanno una pre-analisi del codice per verificare che non ci siano errori prima dell’esecuzione).
Se un programma utilizza librerie esterne (le librerie interne sono già presenti nel runtime), può essere necessario preparare prima un pacchetto build di sorgenti (una specie di linking di codice sorgente), che contiene tutto il codice che dovrà essere eseguito.
L’esecuzione di codice interpretato può essere eseguito in qualsiasi ambiente sia previsto un runtime, senza una fase di build specifica per una determinata macchina. Questo significa però che prima di tutto bisogna installare il runtime, e poi anche avere prestazioni inferiori, perchè l’interpretazione del codice e la sua esecuzione avvengono in tempo reale e sono quindi più lente di una compilazione preliminare. Esempi di linguaggi interpretati sono Python e Javascript.

La Virtual Machine e la compilazione JIT
Alcuni linguaggi (come Java e C#) hanno un processo di build ibrido.
Con questa tecnologia il codice originale viene compilato in un linguaggio macchina speciale, detto Bytecode in Java e IL in .NET. Questo codice macchina è poi eseguito da un runtime speciale chiamato JVM Java Virtual Machine per Java o CLR Common Languare Runtime per .NET). E’ quindi necessario installare questo runtime, anche se spesso già preinstallata col sistema operativo.
L’obiettivo è unire i vantaggi della compilazione (un solo eseguibile) e dell’interpretazione (esecuzione multipiattaforma) con però lo svantaggio di prestazioni non elevate. Questo limite è stato però ben presto superato con un meccanismo chiamato compilazione Just in Time (JIT) che compila il codice in vero codice binario nativo della macchina su cui viene eseguito alla prima esecuzione, cioè dopo il deploy, in alternativa alla compilazione tradizionale, detta Ahead Of Time (AOT), che viene svolta prima del deploy.
La compilazione JIT è stata poi estesa anche a molti linguaggi interpretati, in particolare su Javascript, che offre oggi prestazioni simili a quelle di un programma compilato.
Validazione
In fase di build è prevista, per la maggior parte dei linguaggi, una fase di prevalidazione del codice, tramite strumenti di verifica formale che controllano la sintassi. La validazione ha un grande ruolo perché aiuta il programmatore sia a verificare che non ci siano errori di sintassi che i sorgenti e le librerie siano corrette, e con gli strumenti giusti, anche a verificare staticamente il codice, per esempio per condizioni che non possono verificarsi o cicli che non hanno via di uscita.
La validazione offre grandi vantaggi al programmatore perché consente, prima dell’esecuzione, di usare automatismi per verificare la correttezza formale del codice, mediante anche meccanismi molto sofisticati. Molti linguaggi moderni di programmazione, in particolare i linguaggi compilati, introducono un insieme di strumenti di verifica del codice a build time:
- tipizzazione “forte“: una variabile è sempre assegnabile solo ad un tipo di dato, questo impedisce erroneamente di assegnare una variabile ad un valore di tipo diverso;
- controllo automatico di variabili con valore nullo: impediscono mentre si scrive codice un errore molto comune in programmazione, quello di elaborare una espressione dove ci sono variabili non assegnate; (presente solo in Kotlin e Swift)
- modificatori di accesso alle variabili: alcune variabili sono inaccessibili in alcune parti del programma, questo impedisce di scrivere dove non si dovrebbe;
- introduzione di vincoli nel passaggio di parametri di funzioni: una funzione chiamata nel modo sbagliato viene considerata un errore prima dell’esecuzione.
- contratti (interfacce) nella programmazione ad oggetti: il programmatore viene avvertito su cosa può fare o non fare un altro oggetto.
- gestione automatica della memoria: non è possibile un accesso diretto alla memoria, così da evitare di creare variabili dimenticandosi di cancellarle quando non si usano più (non presente in C/C++)
Tuttavia la correttezza formale non garantisce la correttezza sostanziale. Potrebbero comunque esserci errori visibili solo in esecuzione, dovuti a errori concettuali o a errori di configurazione, librerie o altri elementi concreti non immediatamente rappresentabili in fase di codifica. Ad esempio potremmo cercare di aprire un file che non esiste, o cercare di usare una variabile non ancora valorizzata.
IDE
Un IDE è una applicazione realizzata per fornire al programmatore tutti gli strumenti necessari per lo sviluppo a compile time,
- un editor di testo che permette di scrivere il codice, con funzioni di evidenziazione di variabili, parole chiave ed errori di sintassi. E’ inoltre possibile avere funzioni di autocompletamento di istruzioni e variabili.
- un accesso rapido al compilatore o interprete tramite scorciatoie di tasti.
- l’IDE ha un debugger integrato che consente di inserire i breakpoint e visualizzare le variabili.
- permette di progettare interfacce grafiche e visuali.
- consente per alcune tecnologie di realizzare già uno schema del progetto senza scrivere il codice iniziale.
- ha tutti gli strumenti necessari per il deploy.
I due IDE oggi più diffusi sono IntelliJ (pensato in particolare per le applicazioni Java o linguaggi di quella famiglia, ma supporta anche Javascript, PHP e Python) e Visual Studio Code (pensato per Javascript, ma che supporta quasi tutti i linguaggi di programmazione tramite plugin).
Altri IDE particolarmente diffusi ma specifici per alcune tecnologie sono Visual Studio (progettato per applicazioni .NET su Windows), XCode (IDE per realizzare applicazioni per dispositivi Apple), Android Studio (variante di IntelliJ per il solo sviluppo per Android) e JavaBeans (per sole applicazioni Java).
Sono presenti anche molti strumenti di sviluppo basati su Web, come Colab Notebooks (per Python, non è un vero e proprio IDE ma consente di creare progetti e testare programmi) e Github codespaces (basato su VS Code).
Linguaggi ed applicazioni
In questa sezione andiamo a vedere quali sono le più diffuse tipologie di applicazioni software realizzate oggi. Successivamente vedremo un elenco di linguaggi e a quali paradigmi ed applicazioni sono associabili.
Tipologie di applicazioni
In questa tabella vediamo le più diffuse tipologie di applicazioni oggi realizzabili:
| Tipologia | Descrizione | Tecnologie e linguaggi |
|---|---|---|
| Applicazione da terminale | Si tratta del più semplice tipo di applicazione, che prevede una interfaccia utente testuale, nessuna grafica ed è utile sia a scopo diattico, sia per realizzare tutti gli quegli strumenti per cui non è necessaria una interfaccia grafica. | Supportata dalla maggior parte dei linguaggi |
| Applicazione desktop grafica | Applicazione con una interfaccia a finestra eseguibile su un pc con un moderno sistema operativo (WIndows, Mac, Linux). | Per realizzare applicazioni con interfaccia grafica è necessario sia conoscere un linguaggio sia utilizzare una libreria o framework grafico per gestire l’interfaccia grafica. I linguaggi più diffusi che supportano pienamente le app desktop sono C++, Java e C#, anche se esistono librerie anche per altri linguaggi. E’ possibile comunque trasformare, con opportuni strumenti, una applicazione HTML-Javascript in una applicazione Destkop. |
| Sito Web (applicazione Web) | Un sito web è una applicazione per la visione di contenuti basata su un browser che visualizza una pagina web basata su linguaggio HTML. CI sono due tipi di pagine: – pagina statica HTML: pagina che viene visualizzata e che non prevede interazione con l’utente, ma solo visualizzazione di contenuti (es. pagina di un giornale online). – pagina web dinamica: in questo caso la pagina è interattiva e si comporta come una vera applicazione, come un social, un gioco online, una app usabile da browser. | La tecnologia di riferimento è HTML-CSS-Javascript, dove i primi due sono linguaggi che servono a descrivere i contenuti, mentre Javascript è un linguaggio che permette di trasformare la pagina web in una vera applicazione. |
| Web Server | Un server web è una applicazione che resta sempre attiva e riceve richieste (normalmente da pc o mobile) tramite una connessione Web HTTP a cui risponde inviando pagine html-css-javascript che verrà visualizzata su browser. | E’ realizzabile da molti linguaggi: i più diffusi sono PHP, Java, C#, Python, Javascript, ecc. |
| Web Service | Un web service è simile ad un web server (la tecnologia è la stessa). La differenza è che un web service non invia pagine html, ma dati. Viene usata sia dai client web (in Javascript) o dalle app mobile. | E’ realizzabile da molti linguaggi, i più diffusi sono Java, C#, Python, Javascript PHP, ecc. |
| App mobile | Si tratta delle app mobile per sistemi iOs o Android. Ha una interfaccia utente touch. | I linguaggi di riferimento sono Java/Kotlin per Android, e Swift per iOs. E’ comunque possibile realizzare app mobile anche in Javascript e C#. |
| applicazione IoT e microcontrollori. | Tipo speciale di applicazione che viene installata su un dispositivo, ad esempio un sensore per il rilevamento dell’inquinamento o una lampadina accendibile da remoto. Le app IoT non hanno una interfaccia utente, ma vengono controllate da remoto tramite una applicazione web. | Si usano molti linguaggi, in particolare C++ o Python. |
| IA | Le applicazioni di intelligenza artificiale basate su Machine Learning sono applicazioni basate che svolgono operazioni di elaborazione senza che sia predisposto un algoritmo ma tramite un modello computazionale preaddestrato. | I linguaggi principalmente usati sono C++ (per la realizzazione del modello) e Python (per l’applicazione vera e propria). |
| Applicazione di calcolo | Applicazione che svolge operazioni di memorizzazione e calcolo molto complesse. | C/C++ ma anche Python (grazie alle potenti librerie scritte in C++). |
| Videogioco | Applicazione gicoo interattiva che dispone di una interfaccia grafica. Presente su piattaforme pc o dedicate (console). | C/C++ (per il motore di gioco) mentre per l’interazione con l’utente si usano C# o Javascript. |
| Libreria | Non è una vera applicazione, ma un modulo che svolge delle funzioni e viene utilizzato dalle altre applicazioni. | Tutti i linguaggi moderni permettono di realizzare librerie, anche per altri linguaggi, tramite il meccanismo delle API. |
| Sistema operativo | Software fondamentale per l’utilizzo di un computer, gestisce tutte le altre applicazioni, la memoria, la cpu e il filesystem. | C (Linux e Mac) o C++ (Windows e Mac). |
Linguaggi
Qui un elenco dei più diffusi linguaggi di programmazione.
| Linguaggio | Descrizione | Paradigmi di programmazione | Principali utilizzi |
|---|---|---|---|
| C | Linguaggio capostipite della programmazione strutturata, ha una facile curva di apprendimento all’inizio ma consente operazioni di elaborazione della memoria più avanzate di altri linguaggi. Per questa ragione è considerato un linguaggio un po’ ostico per operazioni complesse. | Programmazione strutturata | Sistemi operativi Applicazioni da terminale. Applicazioni di calcolo. Videgiochi. |
| C++ | E’ una estensione del C, ma con la programmazione ad oggetti e strutture dati più evolute. | Programmazione strutturata. Programmazione ad oggetti. | Sistemi operativi Applicazioni da terminale. Applicazioni di calcolo. Videgiochi. IA. IoT. |
| Java | Linguaggio per la programmazione ad oggetti pura, multipiattaforma. Recentemente ha introdotto anche elementi funzionali. | Programmazione ad oggetti. Programmazione funzionale (parziale). | Applicazione desktop. App mobile. Web Server. Web Service. |
| C# | Linguaggio per la programmazione ad oggetti ma anche funzionale, multipiattaforma. | Programmazione ad oggetti. Programmazione funzionale (parziale). | Applicazione desktop. App mobile (ibrida). Web Server. Web Service. Videogiochi. |
| PHP | Linguaggio per applicazioni web lato server, derivato dal C. | Programmazione ad oggetti. | Web Server. Web Service. |
| Python | Linguaggio molto semplice da imparare, ha come applicazioni principali il calcolo | Programmazione ad oggetti (parziale). Programmazione funzionale (parziale). | Applicazioni di calcolo. IA. IoT. Web Server. Web Service. Applicazioni desktop (ibride). |
| Javascript | Linguaggio che nasce per i browser per rendere interattive le pagine web. Grazie a NodeJS è diventato un linguaggio per realizzare molti tipi di applicazioni. | Programmazione ad oggetti (parziale). Programmazione funzionale (parziale). | Applicazione Web client. Applicazione desktop. App mobile (ibrida). Web Server. Web Service. Videogiochi. |
| Typescript | Estensione di Javascript che aggiunge una migliore gestione sia della programmazione ad oggetti che funzionale. | Programmazione ad oggetti. Programmazione funzionale. | Applicazione Web client. Applicazione desktop. App mobile (ibrida). Web Server. Web Service. Videogiochi. |
| Swift | Linguaggio per app mobile Apple, recentemente è stato esteso per realizzare molti tipi di applicazioni. | Programmazione ad oggetti. Programmazione funzionale. | App mobile (iOs). App desktop. Web Server. Web Service. |
| Kotlin | Linguaggio per app mobile Android, nasce come evoluzione di Java recentemente è stato esteso per realizzare molti tipi di applicazioni. | Programmazione ad oggetti. Programmazione funzionale (parziale). | Applicazione desktop. App mobile (Android). App mobile (iOs ibrida) Web Server. Web Service. Videogiochi. |
| Cobol | Linguaggio per la gestione di grandi applicazioni per aziende. | Programmazione strutturata e procedurale. | Oggi ampiamente sostituito da Java è ancora in uso su vecchi mainframe. |
| Fortran | Linguaggio per il calcolo ed operazioni matematiche. | Programmazione strutturata e procedurale. | Oggi ampiamente sostituito da molti linguaggi, ha ancora settori di nicchia che lo utilizzano. |
| Scala | Linguaggio per il calcolo, la gestione di dati. | Programmazione funzionale. | Linguaggio principalmente dedicato alle applicazioni di grandi moli di dati (Big Data), in parte sostituito da Python. |
Qui una parziale mappa evolutiva di questi linguaggi.

