← Torna a Impara

Perchè Zig quando ci sono già C++, D e Rust?

Nessun intervento nascosto sul flusso di esecuzione

Se vedi del codice Zig e non sembra che stia chiamando una funzione, allora non lo sta facendo. Questo significa che il seguente codice chiamerà sicuramente solo foo() e poi bar(), e questo è garantito anche senza conoscere i tipi di dato utilizzati:

var a = b + c.d;
foo();
bar();

Esempi di controllo nascosto del flusso di esecuzione:

Lo scopo di questa scelta progettuale è migliorare la leggibilità.

Nessuna allocazione dinamica nascosta

Zig ha un approccio schivo riguardo le allocazioni dinamiche. Non c'è alcuna parola chiave new o parte del linguaggio che fa uso di allocazioni dinamiche (per es. l'operatore di concatenazione di stringhe[1]). L'intero concetto di heap è gestito dal codice di librerie e applicazioni, non dal linguaggio.

Esempi di allocazioni dinamiche nascoste:

Quasi tutti i linguaggi garbage-collected hanno allocazioni dinamiche nascoste qua e là, dato che il garbage collector nasconde le prove con la fase di liberazione della memoria.

Il problema principale delle allocazioni dinamiche nascoste è che impediscono la riusabilità di un insieme di codice, limitando senza alcuna ragione il numero di ambienti appropriati che possono fare uso di quel codice. In sostanza, ci sono casi d'uso in cui è indispensabile poter essere sicuri che il flusso di esecuzione e le chiamate di funzioni non abbiano gli effetti collaterali delle allocazioni dinamiche, quindi un linguaggio di programmazione può essere adatto a questi casi d'uso solo se può dare questa garanzia.

In Zig, alcune parti della libreria standard forniscono e interagiscono con gli allocatori dinamici, ma sono Caratteristiche opzionali della libreria standard, non sono parte del linguaggio. Se non inizializzi alcun allocatore dinamico, hai la certezza che il tuo programma non allocherà nello heap.

Ogni funzione della libreria standard che richiede allocazioni dinamiche accetta un parametro di tipo Allocator per poterlo fare. Questo significa che Zig supporta le piattaforme puramente hardware. Per esempio puoi usare std.ArrayList e std.AutoHashMap in sistemi embedded!

Gli allocatori personalizzati rendono la gestione della memoria una passeggiata. Zig ha un allocatore di debug che gestisce la sicurezza della memoria in caso di use-after-free e double-free. Automaticamente, rileva i memory leak e ne fornisce lo stack trace. C'è un allocatore ad area che permette di combinare un qualunque numero di allocazioni in una sola, per poi liberare l'area di memoria tutta insieme, invece di gestire singolarmente ogni allocazione. Allocatori a uso specifico possono essere utilizzati per migliorare le prestazioni o l'utilizzo di memoria, per soddisfare i requisiti di qualunque applicazione.

[1]: In effetti c'è un operatore di concatenazione di stringhe (o meglio, concatenazione di array), ma funziona solo in fase di compilazione, quindi in ogni caso non esegue alcuna allocazione dinamica a runtime.

Nessun trattamento speciale per le librerie standard

Come suggerito nei paragrafi precedenti, Zig ha una libreria standard completamente opzionale. Ogni API della libreria standard viene compilata nel tuo programma solo se la usi. Che si decida o meno di linkare a libc, Zig offre lo stesso tipo di supporto. Zig aiuta lo sviluppo per sistemi hardware/embedded e applicazioni ad alte prestazioni.

Così si prendono due piccioni con una fava; per esempio in Zig, i programmi WebAssembly possono usare le funzioni comuni della libreria standard, e comunque risultare in binari minuscoli in confronto ad altri linguaggi che supportano la compilazione per WebAssembly.

Un linguaggio portabile per le librerie

Una dei pilastri della programmazione è il riuso del codice. Purtroppo, nella pratica, si finisce col dover reinventare la ruota più e più volte. Spesso questo sforzo è giustificato.

Un gestore di pacchetti e sistema di build per progetti esistenti

Zig è una toolchain, un insieme di strumenti, oltre a essere un linguaggio di programmazione. Include un sistema di build e gestione di pacchetti che sono utili persino nel contesto di un progetto C/C++ tradizionale.

Non solo puoi scrivere codice Zig invece di C o C++, ma puoi usare Zig come sostituto di autotools, cmake, make, scons, ninja, eccetera. In più, hai a disposizione un gestore di pacchetti per le dipendenze native. Questo build system è adatto persino a progetti scritti interamente in C or C++. Per esempio, sostituendo il build system di ffmpeg con quello di Zig, diventa possibile compilare ffmpeg su ogni piattaforma supportata per ogni piattaforma supportata, usando solo un download di Zig da 50 Mib. Per i progetti open source, questa semplificazione della compilazione da codice sorgente - e cross-compilazione - può fare la differenza tra l'attirare o il perdere preziosi contributori.

I gestori di pacchetti di sistema come apt-get, pacman, homebrew e altri sono fondamentali per l'user-experience degli utenti finali, ma possono essere insufficienti per le necessità degli sviluppatori. Un gestore di pacchetti specifico per un linguaggio può fare la differenza tra il non avere contributori e averne molti. Per i progetti open source, la difficoltà di riuscire anche solo a compilare il progetto è un grande ostacolo per i potenziali contributori. Per i progetti C/C++, avere dipendenze può essere fatale, specialmente su Windows, che non ha un suo gestore di pacchetti. Persino con la compilazione dello stesso Zig da sorgente, la maggior parte dei nostri potenziali contributori hanno difficoltà con la dipendenza da LLVM. Zig offre ai progetti un modo per dipendere direttamente dalle librerie native, ma senza che gli utenti debbano per forza avere la versione corretta disponibile nel loro gestore di pacchetti, e in un modo che compila praticamente sempre al primo tentativo a prescindere dalla piattaforma su cui si sta compilando, o per cui si sta compilando.

Altri linguaggi includono un gestore di pacchetti, ma non eliminano la necessità delle dipendenze di sistema come fa Zig.

Zig può sostituire il build system di un progetto con un linguaggio ragionevole che fornisce un'API dichiarativa per compilare i progetti, e che si occupa anche della gestione dei pacchetti, rendendo quindi possibile dipendere davvero da altre librerie C La possibilità di avere dipendenze apre la strada a livelli di astrazione più alti, e quindi alla proliferazione di codice ad alto livello riutilizzabile.

Semplicità

C++, Rust e D hanno così tante funzioni disponibili che possono finire col distrarre dall'effettivo significato del codice che si sta scrivendo. Così ci si ritrova a debuggare la propria conoscenza del linguaggio di programmazione, invece di debuggare il programma.

Zig non ha macro, eppure è abbastanza potente da esprimere programmi complessi in modo chiaro e senza ripetizioni. Persino Rust ha delle macro "speciali" come format!, che è implementata direttamente nel compilatore. Invece in Zig la funzione equivalente è implementata nella libreria standard, senza il bisogno di aggiungere controlli specifici nel compilatore.

Strumenti

Zig può essere scaricato dalla sezione download. Sono disponibili archivi compressi per Linux, Windows e macOS. La seguente lista indica cosa ottieni con uno di questi archivi: