Penso che ci sia una distinzione da fare, tuttavia non è necessariamente tra "Compilato" e "Gestito". Questi non sono opposti; una lingua può essere compilata e non gestita, interpretata (non compilata) e gestita, o entrambi, o addirittura nessuno dei due.
Un linguaggio "compilato" è semplicemente un linguaggio in cui esiste un passaggio che trasforma il codice sorgente scritto dallo sviluppatore in un "bytecode" più regolare che è ciò che viene eseguito dalla macchina. La "macchina" può essere il processore effettivo o una "macchina virtuale" che esegue operazioni aggiuntive sui bytecode per tradurle in istruzioni "native" della macchina. L'antonimo di un linguaggio "compilato" è un linguaggio "interpretato", in cui il codice sorgente viene trasformato in istruzioni bytecode in fase di esecuzione, riga per riga man mano che vengono eseguite, senza una fase di compilazione. Un ibrido tra loro è "jitting", da "JIT" (Just In Time), che di solito è interpretato come un passaggio una tantum dalla macchina esecutiva;
Una lingua "gestita" è una lingua progettata per produrre programmi che vengono consumati all'interno di un ambiente di runtime specifico, che include quasi sempre un interprete bytecode; una "macchina virtuale" che accetta il codice del programma ed esegue una trasformazione aggiuntiva specifica per macchina o ambiente. L'ambiente può anche includere la gestione della memoria, come un "garbage collector" e altre funzionalità di "sicurezza" intese a mantenere il programma operativo all'interno della sua "sandbox" di spazio e strumenti, tuttavia tali funzionalità non sono il solo dominio dei runtime "gestiti" . Praticamente tutti i linguaggi interpretati possono essere considerati gestiti, poiché richiedono che l'interprete sia in esecuzione sotto le righe del codice "utente" in esecuzione. Inoltre, i linguaggi JVM e .NET (Java, Scala, C #, VB, F #, IronWhatever) sono compilati in un linguaggio intermedio o IL, che è superficialmente simile per forma e funzione a un linguaggio di assemblaggio binario, ma non aderisce al 100% a nessun set di istruzioni "native". Queste istruzioni sono eseguite da JVM o dal CLR di .NET, che le traduce efficacemente in istruzioni binarie native specifiche dell'architettura della CPU e / o del sistema operativo della macchina.
Pertanto, le lingue possono generalmente essere descritte come "compilate" o "interpretate" e come "non gestite" (o "native") e "gestite". Esistono linguaggi che possono essere descritti come una qualsiasi combinazione di questi ad eccezione del possibile "interpretato nativo" (che sarebbe vero solo per i codici operativi esadecimali scritti a mano, dove ciò che è scritto dallo sviluppatore è ciò che viene eseguito); se si considera il livello di interpretazione come un "runtime" (di cui è facile discutere e per cui è difficile discutere), tutti i linguaggi interpretati vengono "gestiti".
Se vuoi essere tecnico, quasi tutti i programmi destinati a un sistema operativo multitasking al giorno d'oggi sono "gestiti"; il sistema operativo creerà una "macchina virtuale" per ogni programma in esecuzione, in cui il programma pensa (o almeno non deve sapere diversamente) che è l'unica cosa in esecuzione. Il codice può effettuare chiamate all'interno di se stesso e verso altre librerie di riferimento come se quel programma fosse l'unica cosa caricata in memoria; allo stesso modo, le chiamate per allocare RAM e altra memoria superiore per archiviare e manipolare dati e dispositivi di controllo sono codificate come se l'intera architettura di memoria fosse disponibile. La VM (e il sistema operativo dietro di essa) quindi traduce vari puntatori di memoria nella posizione effettiva del programma, i suoi dati e si aggancia ai driver di dispositivo, ecc. Ciò avviene spesso applicando un offset di memoria (ogni VM riceve un blocco di 2 GB o qualunque sia la memoria, a partire dall'indirizzo X che il programma può trattare come se X fosse l'indirizzo 0) e come tale è molto economico da fare, ma ci sono altre cose di cui è responsabile il kernel del sistema operativo, come la pianificazione dei processi e la comunicazione tra processi, che sono più complicato da gestire. Tuttavia, questo modello di base non viene generalmente considerato "gestito", poiché il programma non deve sapere che è gestito da una macchina virtuale ed è spesso responsabile di mantenere "pulita" la memoria allocata. Un programma progettato per essere eseguito sulla riga di comando di MS-DOS può essere eseguito su sistemi operativi Windows più recenti che non hanno nemmeno l'ambiente MS-DOS al di sotto di essi; al programma viene invece assegnato un ambiente "console virtuale" e purché non tenti di lasciare questa "sandbox"