Perché Heroes

· rebel rebel

Heroes nasce da due vincoli: il codice deve essere facile da leggere per un modello e deve poter usare le librerie C.

Gli errori ricorrenti dei modelli · sound and vision

I modelli che generano codice commettono errori ricorrenti: scambiano argomenti dello stesso tipo, dimenticano un caso, usano un nome non dichiarato o una parola chiave di un altro linguaggio. Heroes è progettato per far rilevare questi errori al compilatore.

Un linguaggio progettato perché ogni sbaglio plausibile di un modello sia un errore di compilazione produrrà programmi funzionanti spendendo meno token in totale di un linguaggio convenzionale, anche se ogni singolo programma costa più token da scrivere.

Una parte della tesi è stata verificata introducendo errori plausibili in programmi funzionanti e contando quelli rilevati dal compilatore. Gli stessi programmi vengono poi controllati con le regole specifiche di Heroes disattivate. Il confronto misura l’effetto di quei controlli. Resta da misurare il risparmio totale di token, cioè dei frammenti di testo che un modello legge e genera. I risultati delle prove → Che cosa è misurato, che cosa è stato scritto prima di misurare e che cosa non si sa ancora →

Perché evitare errori può far risparmiare token

costo reale = token del programma × (1 + tasso di riscrittura)

Accorciare la sintassi riduce i token necessari per scrivere un file. Correggere un errore richiede invece altri passaggi: il modello legge il messaggio, rilegge il codice, riscrive una funzione e riprova la compilazione. Evitare una correzione può quindi far risparmiare più token di una sintassi più breve.

Per questo Heroes usa dichiarazioni esplicite e forme brevi per le operazioni comuni. Richiede qualche parola in più dove serve a rendere riconoscibile un errore.

Usare le librerie esistenti

Heroes usa le librerie C per file, socket, database e grafica. Sviluppare e mantenere librerie proprie richiederebbe troppo lavoro per un progetto seguito da una sola persona. Heroes fornisce quindi le operazioni essenziali e usa le librerie C esistenti per il resto.

matematica oltre l’aritmetica  →  libm          file, socket   →  libc
espressioni regolari           →  PCRE2         HTTP           →  libcurl
JSON                           →  cJSON         SQL            →  SQLite
grafica, audio, terminale      →  SDL, raylib, ncurses

Per usare una libreria, dichiari le funzioni che ti servono. Il nome nella prima riga indica l’header, il file che descrive le funzioni e i tipi della libreria. Clang, il compilatore C, verifica le tue dichiarazioni usando quel file.

extern "math.h" link "m"
    function sqrt(x: f64) -> f64
    function pow(base: f64, exponent: f64) -> f64
    function floor(x: f64) -> f64
examples/gallery/08-ffi.hero, righe 12–15

Una persona o un modello potrebbe dichiarare una funzione C che non esiste. Il compilatore segnala anche questo errore, verificando l’header della libreria:

error[ffi_unknown_name]: `math.h` declares no `sqrtt` — clang read the header and could not find it
  at ffi-demo.hero:2:5
    |
  2 |     function sqrtt(x: f64) -> f64
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  note: an `extern` names what the header already has (§4.19): check the spelling, or name the header that does declare `sqrtt`

Clang usa l’header reale della libreria. Verifica sia i nomi sia le dimensioni dei tipi nelle posizioni che lo richiedono e segnala gli errori prima dell’esecuzione. Heroes non deve mantenere una seconda descrizione della libreria da aggiornare.

L’header permette di verificare le dichiarazioni. Restano valide anche le regole di Heroes: pow(base:, exponent:) riceve due valori dello stesso tipo, quindi la chiamata deve specificare i nomi degli argomenti.

Le operazioni disponibili comprendono print, len, push, slice, sort, le conversioni tra tipi, map, filter e fold. Ogni aggiunta richiede una decisione registrata.

Usare le librerie C deve essere semplice quanto scrivere in Heroes. Se una libreria non è accessibile da Heroes, chi la vuole usare deve scrivere altro codice C. Il progetto cerca di ridurre questa necessità. I programmi che usano il C →

Perché il compilatore emette C

Heroes traduce il tuo programma in C e affida a clang la produzione dell’eseguibile. Questo permette a clang di verificare le dichiarazioni delle funzioni C sugli header delle librerie a ogni compilazione. Il progetto iniziale prevedeva di generare direttamente codice macchina; è stato modificato per usare questi controlli. La scelta dipende dalla verifica delle librerie, non da un vantaggio di velocità.

Sette parole possono aprire una riga

Un file è una lista di dichiarazioni, e ognuna comincia con la parola che dice cosa stai dichiarando. constant per un valore fisso, function, record per un gruppo di campi con un nome, variant per un valore che arriva in più forme. Altre tre non dichiarano niente sui tuoi dati: use per un altro file, test, e extern per quello che viene dal C. La lista finisce lì. Nessuna classe, nessuna interfaccia, e in nessun punto una variabile globale che chiunque possa modificare.

# A position on the integer grid.
record Point
    x: i64
    y: i64

# A rectangle, by two corners.
record Rect
    corner: Point
    extent: Point
examples/gallery/01-points.hero, righe 6–14

Puoi scrivere le dichiarazioni in qualsiasi ordine. Due funzioni possono chiamarsi a vicenda senza dichiarazioni anticipate. Durante la compilazione, Heroes riconduce il codice a sette costrutti interni, le forme di base usate per rappresentare il programma.

Perché le stringhe hanno dei buchi

Una stringa può portare dei valori, e a trasformare {n} nel testo di n è una f prima della virgoletta d’apertura.

function line(at: i64, of: i64, star: Star) -> str
    return f"{at}/{of} {star.name} at magnitude {star.magnitude}"
examples/gallery/12-interpolation.hero, righe 20–21

Perché la f: dentro le stringhe normali la graffa era già in uso, e oltre duecento stringhe del compilatore stesso ne contengono una, quindi una stringa con dei buchi lo dice dal primo carattere e tutte le altre restano come prima. Perché qualsiasi espressione: elencare le forme ammesse costava più token di specifica che ammetterle tutte, e a decidere è stato il conteggio. Cosa può stare in un buco, cosa scrive {{ e cosa dice il compilatore davanti a un buco senza testo stanno nel capitolo. Le stringhe, buchi compresi → L’esempio intero →

Le regole del linguaggio · fashion

Cosa Heroes fa male

Ognuna è una scelta, e questo è quello che costa.

Domande frequenti · quicksand, avoided

Perché niente null, perché gli argomenti nominati, perché ogni assegnamento è una copia, quanto è veloce, cosa costa, se fidarsi di un compilatore scritto da un’AI: le domande che ci si fa prima di provare Heroes hanno una pagina loro, ognuna con una risposta di poche righe. Domande frequenti →

Per proseguire: Tutto il linguaggio è un file solo, abbastanza piccolo da darlo a un modello e lasciare spazio al tuo programma. Tutti i programmi del repository sono scritti così, e quattro comandi costruiscono il compilatore.