Intro
Per premettere questo, ho programmato molto poco in Lua. Ho fatto questo gioco super semplice, e attualmente sto lavorando ad un altro. Tuttavia, è stato abbastanza per farmi vedere alcuni dei lati negativi della programmazione in Lua.
Lamentele
Ecco le mie tre lamentele principali:
1) Tipizzazione dinamica e (un po’) debole
2) Tutto è un errore di runtime
3) Mancanza di classi
Esempi
Dynamic Typing/Lack of Type Annotations
Consideriamo una funzione come esempio specifico.
function Ent:update_state(cmd, params) if cmd == 'at' then self.x, self.y = params.x, params.y endend
Prima di tutto, la lettura della funzione stessa diventa difficile. Cosa prende questa funzione? E cosa restituisce, se c’è qualcosa? Non otteniamo queste informazioni guardando la firma della funzione. Invece, dobbiamo leggere il corpo della funzione. Per funzioni semplici, questo va bene. Ma per funzioni più lunghe e complesse, determinare il tipo di ritorno diventa una seccatura.
Inoltre, leggere/scrivere/debuggare le chiamate di funzione diventa difficile. Possiamo passare un valore di qualsiasi tipo a cmd
! Se eseguiamo ent:update_state(4, …)
, la ent
non si aggiornerà. Ma invece di catturare questo come un errore di tipo, dovremo fare il debug a runtime.
In generale, i linguaggi con tipizzazione dinamica sono più difficili da leggere. Se volete sapere il tipo di una variabile, dovete pensare al percorso di esecuzione del codice, invece di poter dare un’occhiata a un’annotazione di tipo (ad esempio Java) o controllare il tipo in un REPL (ad esempio usando ghci per controllare i tipi Haskell). Il linguaggio Hack è un’eccezione. È tipizzato dinamicamente, ma fornisce ancora il controllo statico del tipo. Con Lua, si ottengono tutti i pro e i contro di un linguaggio dinamicamente tipizzato. È super facile scrivere codice e altrettanto difficile garantirne la correttezza.
Erori di runtime/silenzioso
function test_func(test_arg) print(test_arg)endtest_func() -- prints 'nil'
Ecco uno scenario che ho incontrato spesso. Ho bisogno di aggiungere/rimuovere/cambiare una funzione. Quindi cambio la funzione, e poi vado in giro e cambio tutte le chiamate. Questo non è troppo male; posso cercare in tutto il progetto e aggiornare le chiamate una per una. Ma cosa succede se ne perdo una? O se aggiungo una nuova chiamata e dimentico che ho cambiato la funzione? Avete indovinato: un errore di runtime!
Altro esempio casuale: 4 / 0 = inf
. Non lancia un errore.
No Classi
C’è questo, che funziona bene. Ma manca ancora un sacco di belle caratteristiche OO: visibilità dei metodi e interfacce per nominarne un paio. Senza le prime, diventa molto facile cambiare lo stato di un oggetto da qualsiasi parte del codice, e molto più difficile ragionare sullo stato degli oggetti.
Non è tutto male
Ok, questi sono tutti gli esempi che ho (per ora). In realtà ho imparato qualcosa di decente mentre scrivevo questo. Stavo per lamentarmi dello scoping globale, ma ho trovato questo. Stavo per lamentarmi della coercizione di tipo, ma non è troppo male (succede solo con stringhe e ints). E si scopre che c’è una versione digitata di Lua! Non l’ho provata, ma sembra promettente. Se state leggendo questo e avete provato typedlua, fatemi sapere com’è nei commenti.
Perché mi sto lamentando?
Mi rendo conto che lamentarsi di tutte queste cose potrebbe sembrare un po’ stupido. Lua è un linguaggio di scripting leggero; le cose che ho menzionato sopra non sono sempre contro. Lua non è progettato per costruire applicazioni grandi e complesse. Ma questo è il motivo per cui sto postando questo nel subreddit Love2D. Sembra che la gente faccia dei giochi piuttosto grandi e complessi con Lua e Love2D. Per esempio, Mari0, Warlock’s Tower, ecc. Come fanno (voi?) a farlo? Non riesco a immaginare di fare un gioco “legale” in Lua/Love2D. Se mi prendessi una pausa per una settimana, probabilmente dimenticherei metà del codice, e perderei troppo tempo solo per cercare di capire i tipi di tutte le mie variabili e funzioni. I giochi di solito usano Lua come linguaggio “collante”, e implementano il resto in C/C++? Fare un grande gioco in Lua è più facile che in altri linguaggi, anche con i problemi che ho menzionato sopra? Perché la gente usa Lua per giochi di grandi dimensioni, se lo fa?
Grazie per aver trovato il tempo di leggere questo :D. E se ho sbagliato qualcosa sopra, per favore fatemelo sapere!
Letture interessanti:
Lua: Parti buone, cattive e brutte
Tipo debole e forte