Intro
Um es vorweg zu nehmen, ich habe sehr wenig in Lua programmiert. Ich habe dieses supereinfache Spiel gemacht und arbeite gerade an einem anderen. Aber es hat gereicht, um mir einige der Nachteile der Programmierung in Lua zu zeigen.
Beschwerden
Hier sind meine drei Hauptbeschwerden:
1) Dynamische und (etwas) schwache Typisierung
2) Alles ist ein Laufzeitfehler
3) Mangel an Klassen
Beispiele
Dynamische Typisierung/Mangel an Typ-Annotationen
Betrachten wir eine Funktion als ein spezifisches Beispiel.
function Ent:update_state(cmd, params) if cmd == 'at' then self.x, self.y = params.x, params.y endend
Zunächst einmal wird es schwierig, die Funktion selbst zu lesen. Was nimmt die Funktion auf? Und was gibt sie zurück, wenn überhaupt? Diese Informationen erhalten wir nicht, indem wir uns die Funktionssignatur ansehen. Stattdessen müssen wir den Körper der Funktion durchlesen. Für einfache Funktionen ist das in Ordnung. Aber bei längeren und komplexeren Funktionen wird die Bestimmung des Rückgabetyps immer schwieriger.
Außerdem wird das Lesen/Schreiben/Debuggen von Funktionsaufrufen schwierig. Wir können einen Wert beliebigen Typs an cmd
übergeben! Wenn wir ent:update_state(4, …)
ausführen, wird ent
nicht aktualisiert. Aber anstatt dies als Typfehler zu erkennen, müssen wir es zur Laufzeit debuggen.
Im Allgemeinen sind Sprachen mit dynamischer Typisierung schwieriger zu lesen. Wenn man den Typ einer Variablen wissen will, muss man über den Ausführungspfad des Codes nachdenken, anstatt einen Blick auf eine Typ-Annotation werfen zu können (z.B. Java) oder den Typ in einer REPL zu überprüfen (z.B. mit ghci, um Haskell-Typen zu überprüfen). Die Sprache Hack ist eine Ausnahme. Sie ist dynamisch typisiert, bietet aber dennoch eine statische Typüberprüfung. Mit Lua erhalten Sie alle Vor- und Nachteile einer dynamisch typisierten Sprache. Es ist super einfach, Code zu schreiben, und ebenso schwierig, die Korrektheit sicherzustellen.
Laufzeit-/Stillstandsfehler
function test_func(test_arg) print(test_arg)endtest_func() -- prints 'nil'
Hier ist ein Szenario, das mir oft begegnet ist. Ich muss eine Funktion hinzufügen/entfernen/ändern. Also ändere ich die Funktion, und dann ändere ich alle Aufrufe. Das ist nicht weiter schlimm; ich kann das ganze Projekt durchsuchen und die Aufrufe einzeln aktualisieren. Aber was, wenn ich einen übersehe? Oder was ist, wenn ich einen neuen Aufruf hinzufüge und vergesse, dass ich die Funktion geändert habe? Sie haben es erraten: ein Laufzeitfehler!
Zufälliges anderes Beispiel: 4 / 0 = inf
. Es löst keinen Fehler aus.
Keine Klassen
Es gibt dieses Beispiel, das ganz gut funktioniert. Aber es fehlen immer noch eine Menge netter OO-Features: Methodensichtbarkeit und Schnittstellen, um ein paar zu nennen. Ohne Ersteres wird es sehr einfach, den Zustand eines Objekts von überall im Code zu ändern, und es ist viel schwieriger, über den Zustand von Objekten nachzudenken.
Es ist nicht alles schlecht
Ok, das sind alle Beispiele, die ich habe (im Moment). Ich habe beim Schreiben dieses Artikels tatsächlich etwas gelernt. Ich wollte mich eigentlich über das globale Scoping beschweren, habe aber das hier gefunden. Ich wollte mich über den Typ-Zwang beschweren, aber es ist nicht so schlimm (es passiert nur mit Strings und Ints). Und es stellt sich heraus, dass es eine typisierte Version von Lua gibt! Ich habe sie noch nicht ausprobiert, aber sie sieht vielversprechend aus. Wenn Sie dies lesen und typedlua ausprobiert haben, lassen Sie mich in den Kommentaren wissen, wie es ist.
Warum beschwere ich mich?
Mir ist klar, dass es ein bisschen dumm erscheint, sich über all diese Dinge zu beschweren. Lua ist eine leichtgewichtige Skriptsprache; die Dinge, die ich oben erwähnt habe, sind nicht immer Nachteile. Lua ist nicht dafür gedacht, große, komplexe Anwendungen zu entwickeln. Aber das ist der Grund, warum ich dies im Love2D Subreddit poste. Es scheint so, als ob die Leute einige ziemlich große und komplexe Spiele mit Lua und Love2D machen. Zum Beispiel Mari0, Warlock’s Tower, etc. Wie machen sie (Sie?) das? Ich kann mir nicht wirklich vorstellen, ein „echtes“ Spiel in Lua/Love2D zu entwickeln. Wenn ich eine Woche Pause machen würde, würde ich wahrscheinlich die Hälfte des Codes vergessen und viel zu viel Zeit damit verschwenden, die Typen all meiner Variablen und Funktionen herauszufinden. Wird Lua in Spielen normalerweise nur als „Klebesprache“ verwendet und der Rest in C/C++ implementiert? Ist es einfacher, ein großes Spiel in Lua zu entwickeln als in anderen Sprachen, trotz der oben genannten Probleme? Warum benutzen Leute Lua für große Spiele, wenn sie es überhaupt tun?
Danke, dass du dir die Zeit genommen hast, das zu lesen :D. Und wenn ich oben etwas falsch verstanden habe, lass es mich bitte wissen!
Interessante Lektüre:
Lua: Gute, schlechte und hässliche Seiten
Schwache und starke Schreibweisen