Úvod
Předem chci říct, že jsem v jazyce Lua programoval jen velmi málo. Vytvořil jsem tuto superjednoduchou hru a v současné době pracuji na další. Nicméně mi to stačilo k tomu, abych si uvědomil některé nevýhody programování v Lua.
Stížnosti
Tady jsou mé tři hlavní stížnosti:
1) Dynamické a (poněkud) slabé typování
2) Všechno je runtime chyba
3) Nedostatek tříd
Příklady
Dynamické typování/nedostatek typových anotací
Uvažujme funkci jako konkrétní příklad.
function Ent:update_state(cmd, params) if cmd == 'at' then self.x, self.y = params.x, params.y endend
Především se stává obtížným samotné čtení funkce. Co tato funkce přijímá? A co vrací, pokud vůbec něco vrací? Tyto informace nezískáme pohledem na signaturu funkce. Místo toho musíme pročíst tělo funkce. U jednoduchých funkcí je to v pořádku. Ale u delších a složitějších funkcí se určení návratového typu stává větším problémem.
Dále se stává obtížným čtení/zápis/odstraňování volání funkcí. Do funkce cmd
můžeme předat hodnotu libovolného typu! Pokud spustíme ent:update_state(4, …)
, ent
se neaktualizuje. Ale místo abychom to zachytili jako typovou chybu, budeme to muset ladit za běhu.
Jazyky s dynamickým typováním se obecně hůře čtou. Pokud chcete zjistit typ proměnné, musíte přemýšlet o cestě provádění kódu, místo abyste se mohli podívat na typovou anotaci (např. Java) nebo zkontrolovat typ v REPL (např. pomocí ghci pro kontrolu typů Haskellu). Jazyk Hack je jednou z výjimek. Je dynamicky typovaný, ale přesto poskytuje statickou kontrolu typů. S jazykem Lua získáte všechny výhody a nevýhody dynamicky typovaného jazyka. Je super snadné psát kód a stejně tak obtížné zajistit jeho správnost.
Runtime/tiché chyby
function test_func(test_arg) print(test_arg)endtest_func() -- prints 'nil'
Tady je scénář, se kterým se často setkávám. Potřebuji přidat/odebrat/změnit funkci. Změním tedy funkci a pak obejdu a změním všechna volání. To není tak špatné; mohu prohledat celý projekt a aktualizovat volání jedno po druhém. Ale co když nějaké vynechám? Nebo co když přidám nové volání a zapomenu, že jsem funkci změnil? Hádáte správně: selhání za běhu!
Náhodný další příklad: 4 / 0 = inf
. Nevyhodí to chybu.
Žádné třídy
Je tu ještě tohle, které funguje v pořádku. Ale stále tomu chybí spousta pěkných OO vlastností: viditelnost metod a rozhraní, abych jmenoval alespoň pár. Bez prvně jmenovaných se stává velmi snadným měnit stav objektu odkudkoli z kódu a mnohem obtížnějším uvažovat o stavu objektů.
Není to úplně špatné
Ok, to je všechno, co mám za příklady (zatím). Vlastně jsem se toho při psaní tohoto článku slušně naučil. Chtěl jsem si stěžovat na global scoping, ale našel jsem tohle. Chtěl jsem si stěžovat na type coercion, ale není to tak hrozné (děje se to jen u stringů a intů). A ukázalo se, že existuje typovaná verze Lua! Ještě jsem to nezkoušel, ale vypadá to slibně. Pokud to čtete a vyzkoušeli jste typedlua, dejte mi v komentářích vědět, jaké to je.
Proč si stěžuji?“
Uvědomuji si, že stěžovat si na všechny tyto věci může vypadat trochu hloupě. Lua je lehký skriptovací jazyk; věci, které jsem zmínil výše, nejsou vždy zápory. Jazyk Lua není určen k vytváření velkých a složitých aplikací. Ale právě proto to píšu do subredditu Love2D. Zdá se, že lidé pomocí Lua a Love2D vytvářejí docela velké a složité hry. Například Mari0, Warlock’s Tower atd. Jak to dělají (vy?)? Nedokážu si moc představit, že bych v Lua/Love2D dělal „legální“ hru. Kdybych si dal týden pauzu, asi bych zapomněl polovinu kódu a ztratil bych příliš mnoho času jen tím, že bych se snažil zjistit typy všech svých proměnných a funkcí. Používají hry obvykle Lua jen jako „lepicí“ jazyk a zbytek implementují v C/C++? Je tvorba rozsáhlé hry v jazyce Lua jednodušší než v jiných jazycích, a to i s problémy, které jsem zmínil výše? Proč lidé používají Lua pro velké hry, pokud to vůbec dělají?“
Děkuji, že jste si udělali čas a přečetli si to :D. A pokud jsem nahoře něco popletl, dejte mi prosím vědět!
Zajímavé čtení:
Lua: Dobré, špatné a ošklivé části
Slabé a silné psaní