Grazie
· sons of the silent ageHeroes riprende idee da altri linguaggi e da lavori di ricerca. Qui trovi gli autori e il contributo di ciascuno.
I crediti indicano le persone e i gruppi che hanno progettato questi linguaggi. Non sono stati consultati sul progetto Heroes e non sono responsabili del modo in cui ne usa le idee.
Le basi e gli strumenti
Il compilatore traduce Heroes in C11 e usa clang per produrre gli eseguibili e verificare le dichiarazioni delle librerie C sui loro header, i file che ne descrivono funzioni e tipi. Il primo compilatore, usato per arrivare a quello scritto in Heroes, era in Rust.
- C: Dennis Ritchie, che l’ha progettato; Ken Thompson, che ha scritto B, il linguaggio da cui è uscito il C, e Unix insieme a Ritchie; e Brian Kernighan, coautore del libro che l’ha insegnato a tutti. Heroes usa il C per accedere alle librerie esistenti.
- LLVM, clang: Chris Lattner. Heroes usa clang per controllare le dichiarazioni delle funzioni C sugli header delle librerie.
- Rust: il team di Rust, e Graydon Hoare, che l’ha avviato. Il primo compilatore usava un insieme ristretto di funzionalità Rust, scelto per facilitarne la conversione in Heroes.
- Zig: Andrew Kelley, e Nim: Andreas Rumpf. Il file C da cui si può sempre ricostruire il compilatore di Heroes sta nel repository, come Zig tiene nel suo il programma già pronto da cui parte per compilarsi, e Nim tiene il C generato dal suo compilatore, con gli script per compilarlo, in un repository a parte, ogni copia fatta da una versione dichiarata dei sorgenti di Nim.
Il modello dei valori
In Heroes, modificare una copia non cambia l’originale. Non si possono creare cicli di riferimenti tra valori, quindi la memoria può essere liberata contando i riferimenti ancora in uso. Non serve un garbage collector che cerchi cicli. Questo modello si basa sui lavori citati qui sotto.
- Hylo, prima Val: Dimitri Racordon, Denys Shabalin, Daniel Zheng, Dave Abrahams e Brennan Saeta, autori di Native Implementation of Mutable Value Semantics. La frase su cui Heroes si appoggia è loro: i riferimenti non possono essere conservati in variabili o campi, quindi tutti i valori formano alberi separati. Questa restrizione evita di dover rilevare cicli o scrivere annotazioni sulla durata dei riferimenti.
- Swift: Chris Lattner, Doug
Gregor, John McCall, Ted Kremenek e Joe Groff. Il copy-on-write, che rinvia la copia dei dati fino a una modifica, il conteggio dei riferimenti e i parametri
inout(che qui sono@) e ivariantcol punto davanti. E l’idea che lo spazio attorno a un operatore ne distingua gli usi: all’inizio di una riga in una lista, Heroes legge un meno attaccato al suo valore come un segno, e rifiuta un meno staccato dal valore, che Swift leggerebbe come una sottrazione. Heroes riprende queste idee senza introdurreclassné le forme di riferimentoweakeunowned. - APL, J, K: Kenneth E. Iverson, Roger Hui e Arthur Whitney. Questi linguaggi mostrano come lavorare con valori interi senza esporre riferimenti modificabili nel codice.
- R: Ross Ihaka e Robert Gentleman. MATLAB: Cleve Moler. Due esempi di uso dei valori con copy-on-write nella statistica e nel calcolo numerico.
Sicurezza senza garbage collector
Heroes punta a impedire gli accessi non validi alla memoria e la corruzione dei dati. I progetti qui sotto hanno studiato come ottenere sicurezza senza un garbage collector, il sistema che cerca e libera dati inutilizzati.
- Cyclone: Dan Grossman, Michael Hicks, Trevor Jim e Greg Morrisett. I riferimenti solo come parametri di funzione, cosa che cancella dal linguaggio le annotazioni sulla durata di vita. Questo progetto usa la loro regola due volte: è la disciplina in cui è stato scritto il compilatore di bootstrap in Rust, ed è il motivo per cui il porting verso Heroes è stato meccanico. Nel repository quella regola porta il loro nome.
- Modula-3: Luca Cardelli, James
Donahue, Lucille Glassman, Mick Jordan, Bill Kalsow e
Greg
Nelson. Il modello per concentrare le operazioni non sicure in una parte riconoscibile e verificabile del programma.
Dalla sua definizione viene anche la forma di
usein Heroes:IMPORT Iè l’abbreviazione diIMPORT I AS I, e lo stesso nome locale non si può usare due volte, quindi unusepuò rinominare quello che porta dentro, e un nome deve essere unico solo dentro un file.
Mantenere piccolo il linguaggio
I linguaggi di Wirth hanno fornito un riferimento per mantenere breve la specifica. Per il compilatore Heroes, il limite riguarda invece la lunghezza dei singoli file: devono restare comprensibili a chi li legge.
- Pascal, Modula, Oberon: Niklaus Wirth, con
Jürg
Gutknecht su Oberon.
recordevariantvengono da qui. E anche la taratura: il rapporto su Oberon in sedici pagine è quanto può essere lunga una specifica. Pascal-P4, circa quattromila righe, ha mostrato una volta quanto poco basta a un compilatore per compilare se stesso; è storia, non un traguardo che questo progetto si è dato. Wirth ha anche scritto un intero sistema operativo in un linguaggio senza puntatori grezzi, e non c’è argomento più forte a favore di tutto questo approccio. Oberon ha eliminato il record con varianti di Modula, che secondo Wirth veniva usato soprattutto per aggirare i tipi, e per questo Heroes ha rifiutato di legare comevariantuna union del C, un tipo i cui campi condividono tutti lo stesso pezzo di memoria. E la regola che il rapporto su Oberon si dà, che quello che non dice si ricava dalle regole che enuncia o è taciuto di proposito, è un criterio che la specifica di Heroes applica a se stessa: dice apertamente che non ci sono funzioni anonime, funzioni scritte sul posto senza un nome, perché niente nelle sue regole permette di ricavarlo.
I tipi e le alternative valutate
- ML: Robin Milner e il
gruppo di Edimburgo, fra cui
Michael J. C.
Gordon. I tipi prodotto e somma, che raggruppano campi o rappresentano casi alternativi. Heroes li esprime con
recordevariant. - La freccia: Alonzo Church.
->in un tipo funzione è una notazione familiare, ed è arrivato fino a Heroes passando per ML, Haskell, Rust, Swift e i type hint di Python senza cambiare forma. È stato tenuto esattamente com’era. - La subroutine: David Wheeler, su EDSAC nel 1951. Qualcuno ha dovuto inventare l’idea di chiamare un pezzo di codice da più di un posto.
- L’inferenza dei tipi: J. Roger Hindley e Robin Milner. Questo è un grazie per una cosa che Heroes non usa: l’inferenza su tutto il programma può rendere più difficile collegare un errore alla sua causa. Sapere esattamente a che cosa si stava rinunciando, e perché, è quello che il loro lavoro rende possibile.
- Rust di nuovo, il team di Rust. Il suo manuale conta due tipi di
istruzione, la dichiarazione e l’espressione, e mette
letfra le dichiarazioni. Anche in Heroes una dichiarazione non è un valore, quindi una scritta come corpo breve di un caso dimatch, la forma che sceglie fra più casi, come in=> x = 5, viene rifiutata già mentre il programma viene letto. Il controllo di Rust per un tipo che contiene se stesso una volta ha esaurito lo stack, la memoria in cui un programma tiene traccia delle sue chiamate, e per questo il controllo di Heroes su un tipo così lo percorre un passo alla volta invece di chiamare se stesso sempre più a fondo. - Rust e Zig insieme: un float, un numero con la parte decimale, non può essere la chiave di una mappa. La mappa di Rust chiede alle sue chiavi l’uguaglianza e un hash, un numero ricavato dalla chiave per ritrovarla, e Zig rifiuta già in compilazione di calcolare l’hash di una chiave float.
- C++: Bjarne Stroustrup, che l’ha progettato, e WG 21, il gruppo di lavoro di ISO e IEC che ne cura lo standard. L’articolo di Stroustrup sui concept dice che un template del C++, un pezzo di codice scritto una volta per molti tipi, nasconde nel suo corpo quello che chiede al suo argomento, e che l’errore compare solo quando il template viene usato, molto dopo il punto della chiamata. Per questo Heroes segnala dentro la funzione scritta per molti tipi, nel punto in cui è scritta, un’operazione che quei tipi potrebbero non permettere.
- Swift di nuovo, e Java:
James Gosling, che
ha progettato Java, e Oracle, che lo sviluppa. In una funzione scritta per
molti tipi, un parametro di tipo (il segnaposto per i tipi su cui lavora) che
non compare da nessuna parte nella sua firma, la riga che ne nomina
parametri e risultato, è un errore dove la funzione è dichiarata, come in
Swift. Uno che gli argomenti lasciano aperto prende il tipo che il contesto
chiede, come Java ricava il risultato di un metodo generico
dall’assegnazione o dal parametro a cui va. Swift ha anche conservato
tutti e due i livelli di un valore che può fallire dentro un valore che può
fallire: il suo
try?appiattisce solo il proprio risultato, e valori annidati così restano legali. Anche Heroes conserva tutti e due i livelli.
Che effetto fa usarlo
Questi linguaggi hanno influenzato la sintassi, i controlli e i comandi di Heroes. Chi li conosce troverà molte scelte familiari.
- Go: Robert Griesemer,
Rob Pike e
Ken Thompson. Un solo
formato canonico senza opzioni, le variabili non usate come errori, una riga
che finisce senza punto e virgola, e la scelta iniziale di non includere i generici.
Gli escape sono divisi come in Go (un escape è una barra rovesciata che
cambia il senso del carattere che segue): quello dell’apice vale solo
in un carattere scritto fra apici, quello delle virgolette solo in un testo
fra virgolette. Una struttura che contiene se stessa direttamente, o dentro
un array, una lista di valori, è rifiutata come un tipo senza dimensione,
come la rifiuta Go, e il messaggio nomina tutto il giro dei tipi, la
correzione che Go ha fatto quando il suo errore ne nominava uno solo. Quello
che una funzione scritta per molti tipi può farne è dichiarato, come nel
progetto dei parametri di tipo di Go, e mai ricavato da quello che il suo
corpo si trova a fare. Come in Go, i tipi ricavati per una chiamata sono gli
stessi in qualunque ordine vengano i suoi parametri, e un argomento con il
tipo scritto conta prima di uno che non ce l’ha. Il tracker di Go,
l’elenco pubblico dei problemi segnalati, è anche la prova di un
limite: ricavare un tipo dal punto in cui un valore viene usato smette di
essere facile da collegare a un solo posto quando le chiamate si annidano,
come in
f(f(f(0))), e Heroes lo fa a un solo livello, da un tipo scritto, da un risultato dichiarato o dal parametro di una funzione che non è generica. - Nim: Andreas Rumpf. Il meccanismo per chiamare funzioni
esterne, il riuso dei risultati di compilazione per ogni modulo, e
nim r, che èheroes run. E anche l’avvertimento che il progetto continua a ripetersi: copia la superficie di Nim, mai la sua implementazione. - Zig: Andrew Kelley. I test nello stesso file del codice da verificare e le stringhe terminate da NUL, il byte zero usato dal C per indicarne la fine.
- ABC: Leo Geurts, Lambert Meertens e Steven Pemberton, al CWI di Amsterdam. L’indentazione come sintassi, senza nessuna parentesi graffa. Guido van Rossum ha lavorato su ABC per anni prima di portarsela in Python, e Peter Landin alla regola aveva dato un nome già nel 1966. Heroes la prende per due motivi insieme: una graffa che nessuno scrive è un token che nessuno spende, e i modelli che scrivono codice hanno letto talmente tanto Python che questo modo di impaginare il codice lo conoscono già.
- Python: Guido van Rossum,
e
Tim
Peters per
import this, che è diventatoheroes this, incluso nel compilatore. È qui. - Odin, Jai: l’autore di Odin, che pubblica come gingerBill, e Jonathan Blow. Un solo modo uniforme di scrivere una dichiarazione, qualunque cosa si stia dichiarando.
- Ruby: Yukihiro Matsumoto. Il ritmo di lettura (blocchi con un nome, argomenti con un nome, catene di punti), usato come riferimento per la leggibilità, senza riprendere il metaprogramming, cioè la possibilità di modificare il comportamento del codice tramite altro codice.
- Unicode: l’Unicode Consortium, in un rapporto curato da Robin Leroy e Mark Davis. Due caratteri invisibili, lo zero-width joiner e il non-joiner, restano ammessi in una stringa, perché la loro guida al trattamento del codice sorgente dice che servono all’ortografia di alcune grandi lingue.
- Haskell: il comitato che l’ha progettato, nominato più giù
per i suoi primi compilatori. Il suo rapporto definisce
filtercome la funzione che restituisce gli elementi che soddisfano la funzione ricevuta, e la specifica di Heroes dice la stessa cosa a parole:filtertiene quello che la funzione accetta. - C di nuovo, nella storia che ne ha scritto Dennis Ritchie: B e il
primo C scrivevano
+=come=+, un errore corretto nel 1976. È la prova dietro il rifiuto di=@, la forma rovesciata di@=, con cui si dichiara una variabile di Heroes che può cambiare: chi legge potrebbe scambiare=@per un=seguito da@.
Messaggi d’errore e codice incompleto
- Rust: il team di Rust, ed Elm: Evan Czaplicki. Insieme hanno dimostrato che la qualità di un messaggio di errore cambia l’esperienza intera di un linguaggio, e che è una cosa che si progetta, non un dettaglio tecnico. Heroes cerca di fornire nei messaggi le informazioni necessarie per correggere un errore senza aprire altri file.
- Idris: Edwin Brady. Agda: Ulf Norell, e
Catarina Coquand sulla prima versione. I buchi tipati, punti incompleti per cui lo strumento indica il tipo atteso: in Heroes
???è un’espressione legale, e il compilatore risponde dicendo che cosa va nel buco. - GCC: il Progetto GNU, e GHC, il Glasgow Haskell Compiler:
Kevin Hammond, che l’ha scritto per primo,
Simon Marlow,
Simon Peyton
Jones e il Glasgow Haskell Team. In Heroes una forma che il compilatore
non sa ancora tradurre è segnalata con un tipo di messaggio a sé. GCC tiene
il suo “sorry, unimplemented” come un tipo a parte, accanto agli
errori e ai warning (gli avvisi che, a differenza di un errore, lasciano compilare il
programma), e in GHC
Sorrysta accanto aPanic, per qualcosa che si sa che non funziona ancora e che non conta come bug.
Immutabilità su larga scala
- Erlang: Joe Armstrong, Robert Virding e Mike Williams. L’immutabilità dei valori e l’isolamento dei processi sono riferimenti per la gestione dei dati. In Heroes, l’indipendenza dei valori serve anche a capire una funzione senza cercare modifiche altrove.
Generare codice C
Heroes genera C e affida a un compilatore C il lavoro necessario per ciascuna macchina. I linguaggi citati qui sotto hanno seguito questa strada prima di Heroes.
- cfront: Bjarne Stroustrup. Il C++ è nato come un programma che emetteva C.
- Nim: Andreas Rumpf. È nominato più su in questa pagina per il modo in cui chiama le funzioni C, e sta anche qui, perché sono la stessa decisione. Il compilatore di Nim scrive C quando nessuno gli chiede altro, e C++, Objective-C e JavaScript sono alternative che si accendono a mano. Un compilatore che scrive C può includere il file che descrive come sono fatte le funzioni di una libreria, ed è questo che fa funzionare quel modo di chiamare le funzioni esterne. Heroes ha preso la stessa strada per lo stesso motivo.
- Vala: Jürg Billeter, Raffaele Sandrini e Rico Tzschichholz. Chicken Scheme: Felix Winkelmann. Cython: Robert Bradshaw e Stefan Behnel. Tre esempi di linguaggi che generano C.
- Haskell degli inizi: progettato da un comitato, fra cui Paul Hudak, John Hughes, Simon Peyton Jones e Philip Wadler. Anche le prime implementazioni di questo linguaggio di alto livello hanno usato il C.
Dove Heroes incontra il C
Un programma Heroes chiama direttamente le librerie C, e gira sopra un runtime scritto in C, il pezzo di programma che sta sotto e tiene in funzione le cose mentre gira. Le regole qui sotto, su che cosa passa fra Heroes e il C, vengono da progetti che avevano lavorato su quel confine prima.
- Rust di nuovo, il team di Rust. In Heroes una union del C si
costruisce nominando uno solo dei suoi campi, come Rust costruisce le sue, e
una costruita con più campi viene rifiutata. Trasformare in una stringa di
Heroes un testo che arriva dal C è un controllo che può fallire e non ripara
niente, come
to_strdi Rust fallisce su un testo che non è UTF-8 valido, il modo più comune di scrivere un testo in byte, accanto a una conversione separata che sostituisce i byte sbagliati, e come Swift scrive a parte la sua conversione che verifica. La documentazione di Rust è la prova contro il passare al C un valore che nessuno ha riempito: chiamaremem::uninitializedha un comportamento non definito, in cui può succedere qualunque cosa, su quasi ogni tipo. Per questo Heroes ottiene un record che una funzione C riempie da una funzione che lo restituisce. Rust segnala una funzione C dichiarata con lo stesso nome e due tipi diversi, ma non fra i suoi crate, i pacchetti che compila separatamente; Heroes la segnala anche fra i suoi moduli, prima che il linker, il programma che unisce i pezzi compilati in un solo eseguibile, metta insieme il programma. Ethread::spawndi Rust chiede che il lavoro affidato a un nuovo thread, una linea di lavoro che va avanti insieme alle altre, gli sia passato per valore, a condizioni scritte nella sua firma. In Heroes, allo stesso modo, il punto in cui nasce un thread controlla quello che vi entra, e lascia passare solo quello che è stato misurato sicuro. - GCC di nuovo, il Progetto GNU. In Heroes una funzione C che dà
memoria si dichiara insieme alla funzione che la restituisce, come l’attributo
mallocdi GCC accoppia chi alloca la memoria con chi la libera. Il C che Heroes scrive azzera da sé una union, perché GCC 15 non promette più che{0}la azzeri tutta. Una lunghezza passata al C si conta nell’unità del C, come l’attributoaccessdi GCC conta gli elementi del tipo puntato, o i byte quando il puntatore èvoid *. E passare al C un puntatore del tipo sbagliato è un errore in ogni file C che Heroes scrive, come l’ha reso GCC 14, perché quei warning “si ignorano facilmente e portano a bug difficili da diagnosticare”, e come fa clang 22 per impostazione predefinita. - Clang di nuovo: Chris Lattner, il suo autore originale, e l’LLVM Developer Group. Nel conteggio dei riferimenti di clang per Objective-C, un valore contato può partire come puntatore nullo, un indirizzo che non punta a niente, e contare in più o in meno un puntatore nullo non fa niente. Il suo analizzatore statico, che cerca errori nel codice senza eseguirlo, mette accanto all’annotazione che prende in carico la memoria quella che la tiene: chi la tiene la restituirà più avanti, e restituire memoria tenuta viene segnalato come restituire memoria che non si possiede.
- Racket: PLT Inc. In Racket, chiamare a mano la funzione che libera un valore annulla l’ultimo rilascio automatico registrato per quel valore. Heroes, perché nessun valore venga liberato due volte, rifiuta in compilazione una chiamata della funzione di liberazione di una libreria C su un valore che il compilatore libererà da sé.
- C di nuovo, nelle parole del suo standard. Il nome di un header
che contiene un apice, una barra rovesciata,
//o/*viene rifiutato, perché il C lascia non definito che cosa succede a un nome così. Heroes non promette niente sui byte di riempimento dentro un record, i vuoti che il C può lasciare fra i suoi campi, perché C11 lascia non specificato il loro valore dopo una scrittura. E dove C99 permette a una funzione di chiedere un array di almeno N elementi, clang controlla l’array passato e dà un warning solo quando è troppo piccolo; Heroes controlla allo stesso modo una lunghezza rispetto al campo del record C in cui va, solo dove quella lunghezza è un numero noto già in compilazione. - Il kernel Linux:
Linus Torvalds, il
suo autore, e la comunità che ci contribuisce. Il
charsemplice del C non ha un segno suo: su alcune macchine può contenere numeri negativi e su altre no. Heroes gliene fissa uno con un’unica opzione del compilatore, uguale su ogni macchina, e una patch per il kernel, il cuore del sistema operativo, proponeva di aggiungere l’opzione opposta. Una proposta di rendere uguale ovunque ilc_chardi Rust è stata chiusa dal suo stesso autore il giorno dopo. - Go e Zig di nuovo. Le opzioni che il pacchetto di una libreria C passa al compilatore sono ammesse parola per parola, con il loro nome intero, come le ammette cgo, il modo in cui Go chiama il C, dopo una falla di sicurezza. Su Windows, le parole con cui un programma viene avviato gli arrivano in WTF-8, una codifica costruita su UTF-8, senza perdere niente, come Go converte quello che Windows gli passa e Zig converte ogni percorso di Windows. In Go, una conversione che perdeva caratteri aveva fatto bloccare la funzione che cancella una cartella con il suo contenuto.
- gnulib: il Progetto GNU. Un float si stampa come lo stampa
gnulib: partendo da una cifra per i valori più piccoli e da un numero fisso,
FLOAT_DIG, per gli altri, si aggiungono cifre finché il testo stampato non si rilegge come lo stesso numero. - Nim di nuovo: Andreas Rumpf. Un programma Nim i cui thread sollevavano errori dentro un valore condiviso da tutto il programma ha liberato due volte la stessa memoria, perché il conteggio dei riferimenti di Nim non è atomico (un passo atomico è uno che nessun altro thread può interrompere a metà). Su questa prova Heroes ha rifiutato di far condividere a più thread i suoi valori contati.
- CPython, l’implementazione di riferimento di Python: Guido van Rossum, il suo autore, con gli sviluppatori principali e la comunità di Python, sostenuti dalla Python Software Foundation; e OCaml: Xavier Leroy, Damien Doligez, Jérôme Vouillon, Didier Rémy e Ascánder Suárez, sviluppato dall’istituto francese di ricerca in informatica e automazione (French Institute for Research in Computer Science and Automation). Tutti e due chiedono a un thread creato dal C di registrarsi prima di eseguire il loro codice. Da quella regola viene quella di Heroes: il suo runtime si accorge di un thread che non conosce e si ferma in modo pulito invece di corrompere la memoria.
- Chromium: Google, il suo autore, e i Chromium Projects, che
Google controlla; e LLVM: Chris Lattner e
Vikram Adve, i suoi
autori, e l’LLVM Developer Group. Su macOS il codice di LLVM chiede,
per un thread che crea, la dimensione dello stack del thread principale,
perché lì gli altri thread ricevono di base 512KB, e Chromium dà a un thread creato il valore più grande fra
quello predefinito e il limite corrente, perché macOS applica quel limite
solo al thread principale. Il runtime di Heroes fa lo stesso: un thread che
crea riceve almeno lo stack del thread che ha eseguito
main, la funzione da cui parte un programma. - Java di nuovo. La specifica della sua macchina virtuale stabilisce
che cosa succede quando lo stack finisce, uno
StackOverflowError, e ammette stack di dimensione fissa o variabile senza sceglierne una. Heroes fa lo stesso: finire lo stack ferma il programma allo stesso modo ovunque, e nessuna profondità è promessa. - D: Walter
Bright, a cui poi si è unito
Andrei
Alexandrescu, e la D Language Foundation; e Zig di nuovo. Lo
scope(exit)di D esegue la sua azione quando si chiude il blocco in cui sta, non dove è scritto, e ildeferdi Zig quando si esce dal suo blocco, il suoerrdefersolo quando la funzione restituisce un errore. Heroes non ha un’istruzione così; il panel che ne ha valutata una ha stabilito che, se mai entrerà, finirà con il suo blocco, come le loro.
Qualcuno c’era arrivato prima
Heroes è arrivato da solo a ciascuna delle regole qui sotto, e solo dopo ha scoperto che qualcuno c’era arrivato prima. Il merito è loro.
- Native Implementation of Mutable Value Semantics: Dimitri Racordon, Denys Shabalin, Daniel Zheng, Dave Abrahams e Brennan Saeta, già nominati più su per Hylo. Oltre alla frase su cui Heroes si appoggia, il loro articolo conteneva già altre due regole di Heroes: il compilatore scrive da sé, per ogni tipo, come copiarne i valori e come eliminarli; e un array tiene il conto dei punti che lo condividono e viene controllato nel momento in cui lo si modifica, così che sia copiato solo quando una modifica lo richiede.
- Ada: Jean Ichbiah per Ada 83, e Tucker Taft da Ada 95 fino al 2012. Fino ad Ada 2012, una chiamata che poteva modificare due dei suoi argomenti li ricopiava indietro alla fine, in un ordine che il linguaggio lasciava non specificato. Ada 2012 ha poi reso illegale la chiamata quando due parametri in cui può scrivere sono la stessa variabile di un tipo semplice, come un numero, e il compilatore sa che lo sono.
- Swift: Chris Lattner, Doug Gregor, John McCall, Ted Kremenek, Joe Groff e Apple. Passare la stessa variabile due volte alla stessa chiamata, in due posti che possono entrambi modificarla, vale come due modifiche sovrapposte, che vanno in conflitto. Il conteggio dei riferimenti è scritto con istruzioni esplicite nel linguaggio intermedio, la forma a metà strada in cui il compilatore traduce un programma prima di arrivare alla macchina. Quando una lista separata da virgole resta aperta, il compilatore di Swift la fa finire a una riga nuova che comincia con una parola che non potrebbe mai aprire un elemento. Una segnalazione di bug portata su GitHub dal vecchio tracker apre il titolo con la sua vecchia sigla fra parentesi quadre e la ripete in una riga del testo.
- Go: Robert Griesemer, Rob Pike e Ken Thompson, che l’hanno progettato, e Google e i contributori, che lo sviluppano. Un calcolo fatto solo di costanti si svolge in modo esatto, una costante con un tipo dichiarato deve starci dentro, e dividere una costante per zero non è permesso. Il nome di un pacchetto da importare viene prima tolto dalle virgolette e solo dopo controllato, e viene rifiutato se è vuoto o se contiene un carattere non ammesso. Una @ in un’opzione passata al linker sui sistemi di Apple permetteva di far eseguire codice qualsiasi, ed è stata registrata come falla di sicurezza. Dalla versione 1.20, un codice scritto una volta per molti tipi di valore, che chiede solo di poterne confrontare i valori, si può usare anche con un tipo il cui confronto può fermare il programma con un errore mentre gira.
- Rust: il team di Rust. Quando una variabile non viene mai usata e un testo fra virgolette la nomina fra parentesi graffe, il compilatore chiede se lì si voleva inserire il suo valore, e suggerisce come scriverlo. Nella forma dei suoi messaggi fatta per essere letta da altri programmi, il punto di un errore è dato da due conteggi di byte dall’inizio del file, contati da zero, il secondo subito dopo la fine, con accanto i numeri di colonna. E il limite fisso ai passi che il compilatore può fare per calcolare una costante è diventato un warning, ripetuto a intervalli sempre più lunghi.
- Zig: Andrew Kelley e la Zig Software Foundation, che lo sviluppa. Un nome dichiarato dentro una funzione non può essere uguale a quello di qualcosa dichiarato più avanti nello stesso file. Una variabile dichiarata modificabile e mai modificata è un errore, e la correzione è dichiararla costante. Una segnalazione sul loro tracker dice che non è accettabile che lo stesso pezzo di codice compili una volta sì e una volta no.
- C#: Anders Hejlsberg, che l’ha progettato, e Mads Torgersen, che lo sviluppa, entrambi in Microsoft. Un nome dichiarato dentro una funzione non può prendere un nome che il codice attorno usa già, e il compilatore lo segnala in qualunque ordine siano scritte le due dichiarazioni. Un calcolo fatto solo di costanti è controllato per impostazione predefinita, e un risultato troppo grande per il suo tipo è un errore già durante la compilazione.
- C: Dennis Ritchie, che l’ha progettato, e WG 14, il gruppo di lavoro di ISO e IEC che ne scrive lo standard internazionale. Lo standard chiede che un calcolo fatto solo di costanti dia un valore che il suo tipo può contenere.
- D: Walter Bright,
a cui poi si è unito
Andrei
Alexandrescu, e la D Language Foundation. Nella descrizione che D dà
della libreria del C, il nome passato a
getenv, la funzione del C che cerca per nome un’impostazione dell’ambiente in cui il programma gira, porta la parolascope, mentre la funzione passata adatexit, che il C conserva per chiamarla quando il programma finisce, non porta nessun segno. - GCC: il Progetto GNU. Quando GCC compila se stesso in più fasi, si confrontano i compilatori della seconda e della terza fase, e se sono diversi di solito è il compilatore della seconda ad aver compilato GCC in modo sbagliato. Il suo strumento che cerca errori nel codice senza eseguirlo sa che la memoria data da una funzione si può restituire correttamente con una qualunque di più funzioni, e segue ogni pezzo di memoria confrontandolo con tutto quell’insieme. Quando ottimizza un programma intero nel momento in cui i suoi pezzi vengono uniti, GCC dà un warning senza che glielo si chieda se file compilati separatamente dichiarano con tipi diversi lo stesso nome, visibile a tutto il programma. Mentre legge un header di sistema GCC non mostra warning; un header è di sistema quando si trova in una cartella scelta dal compilatore, o in una aggiunta con un’opzione che la dichiara tale. E un’istruzione scritta nel sorgente per cambiare come vengono segnalati i warning vale più di qualunque opzione con cui il compilatore è stato avviato.
- Clang: Chris Lattner,
il suo autore originale, e l’LLVM Developer Group. Nei suoi controlli
per il codice eseguito da più thread nello stesso momento,
l’annotazione su una funzione che prova a prendere
qualcosa e può non riuscirci comincia con vero o falso
(
trueofalse), la risposta con cui la funzione dice di esserci riuscita. - Microsoft SAL: Microsoft, il cui linguaggio di annotazioni per il
codice sorgente descrive come una funzione usa quello che riceve e che cosa
garantisce quando finisce. Una funzione porta al massimo
un’annotazione
_Success_, e quell’annotazione dice a quale condizione la funzione è riuscita.
Le scelte da valutare con cautela
Il progetto ha studiato anche i limiti e i costi delle scelte di altri linguaggi. Questi precedenti aiutano a capire quali soluzioni adottare e quali evitare. Quello che qui è stato rifiutato, e chi lo ha rifiutato, ha una pagina sua: i no di Heroes →
- Lua, con Nelua e Pallene: Roberto Ierusalimschy, Luiz Henrique de Figueiredo e Waldemar Celes. Il precedente di un linguaggio piccolo che compila, e il costo di convertire i dati di una tabella universale prima e dopo le chiamate C. Heroes ha rinunciato alla tabella universale per quel motivo.
- APL di nuovo, nella direzione opposta: la notazione ultracompatta è l’unico punto in cui questo progetto cita Iverson contro se stesso. Heroes preferisce forme più esplicite per aiutare i modelli a leggere e generare codice.
- R e MATLAB di nuovo: documentano i costi delle copie quando si modificano dati condivisi. Anche in Heroes, una modifica può richiedere di copiare la struttura: è un costo da considerare nei cicli.
- Unison: Paul Chiusano e Rúnar Bjarnason. Il codice conservato come albero con i nomi come etichette: l’origine di un’idea che qui è stata esplorata a lungo e poi abbandonata in favore di una sola sintassi leggibile.
E il nome
David Bowie, per “Heroes” (1977), la canzone e l’album. Il nome conserva le virgolette dell’album. Da Bowie viene anche il libro da cui è nato il linguaggio. I riferimenti musicali restano nei testi del progetto e non compaiono nei messaggi d’errore o nei nomi delle librerie.
- hunky dory l’album stesso, 1971
- changes Hunky Dory, 1971
- quicksand, avoided Quicksand, su Hunky Dory, 1971
- five years Ziggy Stardust, 1972
- moonage daydream Ziggy Stardust, 1972
- lady stardust Ziggy Stardust, 1972
- rebel rebel Diamond Dogs, 1974
- speed of life Low, 1977
- sound and vision Low, 1977
- a new career in a new town Low, 1977
- heroes “Heroes”, 1977
- sons of the silent age “Heroes”, 1977
- fashion Scary Monsters, 1980
Le righe in oro accanto ad alcuni titoli di sezione sono canzoni di Bowie. Sono tutte e dodici qui sopra, dal disco più vecchio al più recente, insieme a quella che dà il nome al linguaggio. Ogni titolo apre la registrazione su YouTube; quando il titolo è di un album, il link apre la voce del disco su Wikipedia.
Poi: il panel, dove cinque giudici valutano le proposte e discutono come adattare queste idee a Heroes.