Tipps für richtiges GML Code formatieren

      Tipps für richtiges GML Code formatieren

      Das ist kein Tutorial
      wie GML funktioniert oder wie man GML Code insgesammt "schreibt",
      sondern hier geht es nur um das "Stylen" des Codes. Tutorial für GML .

      Immer wieder kommt Code der, kurz ausgedrückt, nach Mist aussieht:

      GML-Quellcode

      1. x = 32 if x = 21
      2. {show_message('bla')
      3. }


      Zuerst kommt der Tipp, dann ein Beispiel wie man es nicht macht und dann wie man den Tipp anwendet:
      • Code
        einrücken, das heißt mit Leerzeichen oder mit der Tab-Taste den Code
        bei if, switch, while oder ähnlichem so einzurücken das man erkennt was
        zu was gehöhrt:

      GML-Quellcode

      1. if (x)
      2. if (a)
      3. show_message("banane");


      wird zu

      GML-Quellcode

      1. if (x) {
      2. if (a) {
      3. show_message("banane");
      4. }
      5. }


      • das Semikolon ( ; ) benutzen (in anderen Programmiersprachen ist das Plicht):

      GML-Quellcode

      1. bla()
      2. return 0

      wird zu

      GML-Quellcode

      1. bla();
      2. return 0;



      • eine Codezeile pro Zeile:

      GML-Quellcode

      1. bla();x = 4;

      wird zu

      GML-Quellcode

      1. bla();
      2. x = 4;


      • Leerzeichen zwischen a = b oder if (a) setzen:

      GML-Quellcode

      1. if(a) {
      2. a=b;
      3. }

      wird zu

      GML-Quellcode

      1. if (a) {
      2. a = b;
      3. }


      Kontrollausdrücke (while (x), if (x), for (a; b; c)) in Klammern setzen:

      GML-Quellcode

      1. if a {
      2. bla();
      3. }

      wird zu

      GML-Quellcode

      1. if (a) {
      2. bla();
      3. }


      == für Vergleiche, = für Zuweisung benutzen (in anderen Programmiersparachen ist if (x = false) noch immer eine Zuweisung!):

      GML-Quellcode

      1. a = x = 4; //würde in anderen Programmiersprache, a und x auf 4 setzen

      wird zu

      GML-Quellcode

      1. a = x == 4;


      • !(Ausdruck) und nicht (Ausdruck) == false benutzen:

      GML-Quellcode

      1. a = b == false;

      wird zu

      GML-Quellcode

      1. a = !b; //true -> false, false -> true


      • var für temporäre Variablen benutzen (besonders in Skripte!):

      GML-Quellcode

      1. a = sin(x);
      2. macheWasMit(a);

      wird zu

      GML-Quellcode

      1. var a; //a ist nun innerhalb des Skriptes/Codeblockes verfügbar, nach Ende wird sie wieder entfernt
      2. a = sin(x);
      3. macheWasMit(a);


      • Für
        boolsche Werte immer true oder false benutzen (nicht 1 oder 0) (in
        anderen Programmiersprachen sind 1 und 0 ints, während true und false
        bools sind):

      GML-Quellcode

      1. showDebug = 0;

      wird zu

      GML-Quellcode

      1. showDebug = false;


      • 'x' für Chars (also einzelene Zeichen) benutzen "abc" für Strings (auch wenn beide im GM letzendlich Strings sind)


      Wieso sollte ich überhaupt die ganzen Tipps befolgen?


      Viele
      IDEs sorgen dafür das der schon Code eingerückt wird (z.B. Visual
      Studio, Eclipse), der Game Maker hängt da leider hinterher. Quellcode
      soll dadurch viel besser zu lesen zu sein und damit ist er besser zu
      "warten" (Bugs finden und fixen), vielleicht umgeht man auch gleich
      einige Bugs oder sie lassen sich schneller finden.

      Anfänger
      können den Code besser verstehen und lernen auch gleich noch wie sie
      selbst "tollen" Code schreiben. Zum anderen soll durch diese Tipps ein
      besserer Übergang zu anderen Programmiersprachen (C, C++, Java, C#...)
      bestehen, einige Tipps sind, wie angemerkt, dort Plicht oder können zu
      Verhalten führen die im GM anders ist (der = Operator z.B.).

      Die
      Tipps sollen nicht zwingend sein, sondern in die Richtung zeigen, jeder
      kann seinen Quellcode so einrücken, formatieren oder gestalten wie er
      will, zum größten Teil entsprechen die Tipps meinen eigenen
      "Coding-Style".

      Du hast selber Tipps?

      Vielleicht
      hast du ja noch irgendeinen Tipp der hier gut reinpassen würde, schreibe
      eine kurze Beschreibung und ein Beispiel (wie man es nicht macht und wie man es macht) dazu und vielleicht bau ich den Tipp ja noch ein.

      Hab den Text hier schnell geschrieben, vielleicht lässt sich einiges verbessern (Rechtschreibfehler und so).
      wupto.net/ Nicht meine Seite!
      We love Koalas.

      GM-D-Spam-o-Meter: 32%
      1.: Da du selbst sagst, dass das kein Tutorial ist, und es beim Programmierstil ähnlich geil werden kann, wie mit Juristen (zwei Leute, drei Meinungen), hab ich das mal zum Diskutieren in die Expertenrunde geschoben und fang auch mal direkt mit den Widerworten an.
      2.: Codestil ist so eine Sache, die man nicht global vorschreiben kann oder sollte, sondern bei der jeder für sich den Weg wählen sollte, mit dem er am besten zurecht kommt. Es gibt zwar Fundis, die mit Sprüchen wie "weil K&R das so sagen" ihre Meinung als die einzig richtige zu rechtfertigen versuchen, aber bis auf einige Ausnahmen, für die gute Begründungen finden lassen (z.B. zwischen if und dem geklammerten Ausdruck dahinter ein Leerzeichen zu setzen, weil if keine Funktion ist), gibt es immer mindestens zwei Möglichkeiten, die auch beide ihre Daseinsberechtigung haben. Deswegen sollte man mit solchen dogmatischen Regeln eher vorsichtig sein. So ein Style Guide ist dann sinnvoll, wenn man selbst ne Gedächtnisstütze braucht oder in einem Team entwickelt und sich auf einen einheitlichen Stil einigen muss, aber anderen einfach so zu sagen, was "richtig" ist, halte ich doch für etwas anmaßend, weswegen dieser ganze Thread eher mit Vorsicht zu genießen ist. Das einzige, was beim Stil wichtig ist, ist, dass er einheitlich ist (weswegen solche Richtlinien in einem Team auch wieder sinnvoll sind), aber das reicht auch schon aus, damit der Code wartbar bleibt.
      3.: Du redest von IDEs, die einen beim Codestil unterstützen. Auch die setzen nur eine Standardeinstellung um, die deren Programmierer vorgegeben hat, und bieten Einstellungen, um der IDE den eigenen Codestil beizubringen.
      4.: Mir fehlt bei vielen deiner Regeln eine Begründung. Wenn mir jemand vorschreiben will, wie ich etwas zu erledigen habe, ist das erste, was ich (mich) frage: "Warum?"

      henrik1235 schrieb:

      eine Codezeile pro Zeile


      Ähm, ja... Du meinst wohl "pro Anweisung". Jedenfalls erinnert mich diese Formulierung an

      §49 ADA schrieb:

      Der Wertsack ist ein Beutel, der auf Grund seiner besonderen Verwendung im Postbeförderungsdienst nicht Wertbeutel, sondern Wertsack genannt wird, da sein Inhalt aus mehreren Wertbeuteln besteht, die in den Wertsack nicht verbeutelt, sondern versackt werden.


      henrik1235 schrieb:

      == für Vergleiche, = für Zuweisung benutzen


      Und warum nicht = für Vergleiche und := für Zuweisungen? Oder, da = ja so uneindeutig ist, == für Vergleiche und := für Zuweisungen?

      henrik1235 schrieb:

      !(Ausdruck) und nicht (Ausdruck) == false benutzen


      Vorsicht! Das ist schon keine Stilfrage mehr, diese Ausdrücke haben unterschiedliche Semantiken. False ist im GM eine Konstante mit dem Wert 0, d.h. mit "== false" testest du genau auf den Wert 0.
      Die Negation macht aus Werten kleinergleich 0 eine 1 und aus positiven Werten eine 0. Insbesondere für Ausdrücke mit negativem Wert bekommst du so bei "== false" eine 0 und bei Negation eine 1.

      Edit: Die Grenze ist nich 0, sondern 0.5; siehe DragonGamer.

      henrik1235 schrieb:

      var für temporäre Variablen benutzen (besonders in Skripte!)


      Auch dies ist keine Stilfrage sondern hat wieder unterschiedliche Semantiken. Wenn die Variablen eines Skripts nicht mit var als lokal deklariert werden, sind sie nach Ausführung des Skripts noch verfügbar, und wenn sie als lokal deklariert werden (d.h. lokal zum Skript), werden gleichnamige Variablen der ausführenden Instanz nicht verändert. Soll heißen, wenn die ausführende Instanz schon eine Variable namens foo hat, und im Skript auf foo geschrieben wird, so wird das foo der Instanz nicht verändert, wenn foo im Skript mit var als lokal deklariert wurde. Das kann je nach Anwendungsfall mal erwünscht sein und mal nicht.

      henrik1235 schrieb:

      Für
      boolsche Werte immer true oder false benutzen (nicht 1 oder 0) (in
      anderen Programmiersprachen sind 1 und 0 ints, während true und false
      bools sind):


      Und wieder frage ich: Warum? Diesmal allerdings nicht, weil es keinen vernünftigen Grund gibt, sondern weil der von dir genannte kein solcher ist. Es geht hier nicht um andere Programmiersprachen, sondern um GML, d.h. was in anderen Sprachen gilt, kann uns hier völlig egal sein und ist keine akzeptable Begründung für irgendwas. Gleiches gilt bei der Frage, ob man Semikola setzen soll. Wenn der Zeilenumbruch ein Semikolon ersetzt und die Länge eines Skripts sich tatsächlich auf die Laufzeit auswirkt (mir war so, als hätte MewX da mal was rausgefunden), wenn man also um jedes Zeichen kämpfen muss, ist es sogar vernünftiger, die Semikola nicht zu setzen. Durch Zeilenumbrüche und Einrückungen bleibt der Code weiterhin les- und wartbar. Und genauso kann ich mir vorstellen (ich weiß es nicht, aber vllt. hat das schonmal jemand untersucht), dass der GM beim Übersetzen der Konstanten mehr Zeit braucht, als wenn man die Werte direkt hinschreibt. In jedem Fall sind 0 und 1 kürzer als die Mnemonics, was beim Golfen hilft, wenn man wieder um jedes Zeichen kämpft.

      henrik1235 schrieb:

      'x' für Chars (also einzelene Zeichen) benutzen "abc" für Strings (auch wenn beide im GM letzendlich Strings sind)


      Und wieder: Warum? Ja, es gibt Sprachen, die einen zwingen, zwischen einzelnen Zeichen und Zeichenketten als unterschiedliche Datentypen zu unterscheiden, und solche Sprachen brauchen dann zwingend unterschiedliche Auszeichnungen für Konstanten dieser Typen (' vs. "), aber der GM ist keine solche Sprache. Hier ist alles entweder eine Fließkommazahl oder ein String. Und da greift wieder, was ich ganz oben geschrieben habe: Es ist egal, welchen Stil man verwendet, solange man ihn einheitlich durchzieht. Und da ist ein Wechsel zwischen unterschiedlichen Anführungszeichen nur aufgrund der Länge eines Strings eher kontraproduktiv.

      Um also nochmal auf den Anfang zurückzukommen: Ich lasse diesen Thread mal als Diskussionsplattform offen, in der man Konventionen besprechen kann, die sich als "best practice" bewährt haben, aber wenn man anderen Vorschriften machen oder sie von seinem Stil überzeugen möchte, sollte man eine vernünftige Begründung angeben können. Und nein, "aber die Sprache hat auch" ist keine vernünftige Begründung.
      Ich versuche hier nicht zu sagen "hey, mach das so!", ich versuche damit den Gedanken anzuspringen, Code überhaupt erst einheitlich zu formatieren, natürlich kann jeder seinen Code selbst formatieren wie er will.
      (Vielleicht hab ich das nicht richtig rübergebracht?)

      Ich sehe den Game Maker als einen Einstieg in die Welt der (Spiele-)Programmierung, daher benutze ich auch den Unterschied zu anderen Programmiersprachen (diese die am meisten "geläufig" sind). Wenn man schon einige Dinge "von Haus" aus umsetzt, wird der Umstieg vielleicht noch einfacherer fallen wird.

      Und warum nicht = für Vergleiche und := für Zuweisungen? Oder, da = ja
      so uneindeutig ist, == für Vergleiche und := für Zuweisungen?
      Lass mich diesen Tipp begründen, = bekommt je nach Kontext unterschiedliche Bedeutung. a = b, dort ist es eine Zuweisung, in Ausdrücke ist es aufeinmal ein Vergleich (a = b = c). Ich habe hier = für die Zuweisung genohmen da es in den bekanntesten Programmiersprachen so benutzt wird, wo wir wieder bei Umstieg sind.

      Vorsicht! Das ist schon keine Stilfrage mehr, diese Ausdrücke haben
      unterschiedliche Semantiken. False ist im GM eine Konstante mit dem Wert
      0, d.h. mit "== false" testest du genau auf den Wert 0.

      Die Negation macht aus Werten kleinergleich 0 eine 1 und aus positiven
      Werten eine 0. Insbesondere für Ausdrücke mit negativem Wert bekommst du
      so bei "== false" eine 0 und bei Negation eine 1.

      In den meisten Fällen mit == false wird geprüft ob der Ausdruck false ergibt, daher versuche ich auch klar einen Unterschied zwischen true/false und 1/0 zu empfehlen.
      Auch dies ist keine Stilfrage sondern hat wieder unterschiedliche
      Semantiken. Wenn die Variablen eines Skripts nicht mit var als lokal
      deklariert werden, sind sie nach Ausführung des Skripts noch verfügbar,
      und wenn sie als lokal deklariert werden (d.h. lokal zum Skript), werden
      gleichnamige Variablen der ausführenden Instanz nicht verändert. Soll
      heißen, wenn die ausführende Instanz schon eine Variable namens foo hat,
      und im Skript auf foo geschrieben wird, so wird das foo der Instanz
      nicht verändert, wenn foo im Skript mit var als lokal deklariert wurde.
      Das kann je nach Anwendungsfall mal erwünscht sein und mal nicht.

      GML-Quellcode

      1. //script1()
      2. for (i = 0; i < 9; i+=1) {
      3. script2(bla(i));
      4. }
      5. //script2()
      6. for (i = 0; i < 8; i+=1) {
      7. bla();
      8. }


      Kann zu einem Verhalten führen was vermutlich so nicht gedacht ist. Lokale Variable hinterlassen/benutzen ist auch nicht gerade toll, besonders dann wenn man die Skripte veröffentlicht, außer natürlich das Skript soll z.B. die Instance bewegen, dabei weiß der Anwender auch das dabei eine der Bewegungsvariablen geändert werden.


      Es geht darum den Code so zu (zumindestens zum größten Teil) zu vereinheitlichen, damit sich Personen weniger damit beschäftigen den Code versuchen zu entziffern.
      Einige Tipps können Bugs verhindern und damit unnötiges Debuggen schon gleich von Anfang zu beseitigen.

      "die Sprache hat das auch so!"

      Codekonventionen für C# (C#-Programmierhandbuch)
      Code Conventions for the Java Programming Language
      Google C++ Style Guide
      Linux kernel coding style
      wupto.net/ Nicht meine Seite!
      We love Koalas.

      GM-D-Spam-o-Meter: 32%

      henrik1235 schrieb:

      Kann zu einem Verhalten führen was vermutlich so nicht gedacht ist. Lokale Variable hinterlassen/benutzen ist auch nicht gerade toll, besonders dann wenn man die Skripte veröffentlicht, außer natürlich das Skript soll z.B. die Instance bewegen, dabei weiß der Anwender auch das dabei eine der Bewegungsvariablen geändert werden.
      CAS hat das sicher bedacht nur wollte er sagen dass man eben nicht immer var benutzen soll sondern immer bedenken was gewollt ist.
      Du hattest es ein wenig so dargestellt als ob mit oder ohne var das selbe wären, nur letzteres "besser".

      Übrigens
      !0.499 wird auch als "wahr" angesehen denn der GM verstehet alles < 0.5 als false und alles andere (inklusive 0.5) als true.
      Also sollte man da wirklich aufpassen..


      Ansonsten habe ich nur einen "Kritikpunkt":
      Meiner Meinung nach wird das Einrücken maßlos überschätzt.
      Wieso soll

      GML-Quellcode

      1. if (x) {
      2. if (a) {
      3. show_message("banane");
      4. }
      5. }

      Übersichtlicher sein als

      GML-Quellcode

      1. if (x)
      2. if (a)
      3. show_message("banane");

      Wenn du mich fragst ist letzteres übrsichtlicher. Es ist insgesamt kürzer und man kann vernünftig von oben nach unten lesen und muss nicht ständig leere Stellen überspringen und schauen wo es weiter geht.
      Bei deutlich längeren Skripten erhöht es die Übersichtlichkeit auch nicht deutlich. Eher im gegenteil denn wenn man durch drei Bildschirm-Höhen aus Code Scrollt weil man z.B. das Ende einer if-Abfrage sucht, verliert man doch sowieso aus den Augen wie weit das Gesuchte genau eingerückt war. Dieses Problem bestünde nicht wenn der GM Linien benutzen würde die das einrücken anzeigen. Das tut er allerdings nicht und man ist man doch wieder darauf angewiesen einfach die richtige, schließende Klammer zu finden und dabei hilft der GM ja durch den highlighter.
      Ich finde man sollte das Einrücken nur dann verwenden wenn es wirklich die übersicht erhöht und niemals mehr als zwei.. höchstens mal drei Einrückungsstufen verwenden.
      Solche sinnvollen Stellen könnten z.B besondere Statements sein (Schleifen, with, etc)
      oder wenn man else's und Einzeiler hat:

      GML-Quellcode

      1. if (b)
      2. show_message('ab')
      3. else
      4. show_message('a')


      Insgesamt sind deine Tips aber schon nützlich und wie CAS richtig gesagt hat, eine Richtlinie.


      Zur Semikolon-thematik:
      Hatte das damals auch nachgeprüft und festgestellt dass es im neueren GM keinerlei Unterschied in der Laufzeit mehr gibt. Früher dürfte das aber anders gewesen sein denn der GM benutzt erst seit 7.0 oder 8.0 diesen mysteriösen "bytecode" bei dessen Erstellung ziemlich sicher Semikolons usw. entfernt werden. D.h. zumindest die "Kompilierzeit" (also die Zeit die zum Exe erstellen gebraucht wird) könnte minimal durch die überflüssigen Zeichen beeinflusst werden.
      Übrigens werden beim Verarbeiten zu Bytecode auch wohl alle möglichen Rechnungen mit echten Zahlen aufgelöst denn in der Laufzeit von a = 1+20*4+3-14; ist im Spiel dann genau so lang wie von a = 70.

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DragonGamer“ ()

      henrik1235 schrieb:

      In den meisten Fällen mit == false wird geprüft ob der Ausdruck false ergibt, daher versuche ich auch klar einen Unterschied zwischen true/false und 1/0 zu empfehlen.


      1.: Diesen Unterschied gibt es im GM aber nicht, da der GM nunmal nur zwei (primitive) Datentypen hat, und true und false nur Konstanten für Zahlen sind.
      2.: Was in den meisten Fällen gemeint ist, spielt keine Rolle. Bei Stilfragen geht es darum, welche von mindestens zwei Schreibweisen mit äquivalenter Semantik verwendet werden soll, damit für den gleichen Zweck immer gleich aussehender Code verwendet wird. Das mag ja alles seinen Sinn haben, aber es setzt eine wichtige Sache voraus: Die zur Diskussion stehenden schreibweisen müssen auch alle äquivalente Semantik haben, und das haben diese beiden Schreibweisen nunmal nicht. Es gibt Eingaben, die bei beiden Ausdrücken unterschiedliche Ausgaben erzeugen, und damit ist dies keine Stilfrage mehr, sondern eine Frage dessen, was genau der Programmierer an dieser Stelle eigentlich will. Genauso wie die Verwendung von var: Mal will man lokale Variablen verändern, mal nicht, wesegen man sich immer wieder überlegen muss, ob man nun var verwendet, oder nicht; zu sagen "verwende immer var" oder "verwende niemals var" ist keine Stilfrage.

      henrik1235 schrieb:

      Ich sehe den Game Maker als einen Einstieg in die Welt der (Spiele-)Programmierung, daher benutze ich auch den Unterschied zu anderen Programmiersprachen (diese die am meisten "geläufig" sind). Wenn man schon einige Dinge "von Haus" aus umsetzt, wird der Umstieg vielleicht noch einfacherer fallen wird.


      Wenn man die Sprache wechselt, gelten ohnehin andere Spielregeln. Jede Sprache hat ihre Eigenheiten, auf die man sich einstellen muss, wenn man diese Sprache lernt. Einen möglicherweise leichteren Umstieg zu versprechen ist somit ein genauso schwaches Argument für irgend eine Code-Konvention, wie "aber diese Sprache macht das doch auch". Du hast z.B. vorgeschlagen bei Zuweisungen Leerzeichen vor und nach dem Zuweisungsoperator zu setzen. Ich kann dir eine Sprachfamilie nennen, bei der du keine Leerzeichen setzen darfst (zumindest nicht vor dem Operator), weil die Variable, auf die geschrieben werden soll, sonst nicht als Variable sondern als Befehl interpretiert wird.
      Nochmal: Es geht hier um GML, und da ist es verdammt nochmal egal, was andere Sprachen so treiben.

      henrik1235 schrieb:



      Microsoft, Oracle, Google und wie auch immer sich die Gruppe nennt, die am Kernel rumschreibt. Das unterstreicht nur, was ich vorher schon gesagt habe: Es ist sinnvoll, Code-Konventionen einzuführen, wenn man gemeinsam an einer Sache arbeitet, aber es gibt nicht den Stil (was man schon an religiösen Streitfragen sieht, die heute noch Communities spalten, z.B. wo öffnende geschweifte Klammern zu stehen haben, oder womit man einrückt (ein Leerzeichen? zwei Leerzeichen? vier Leerzeichen? Tabulator?)), selbst, wenn man sich nur auf eine Sprache beschränkt. Das von dir verlinkte sind jeweils nur die Richtlinien, die diese vier Gruppen für sich verwenden und für den Rest der Welt veröffentlicht haben.

      Außerdem finde ich das ziemlich einseitig, dass, wenn du dich schon auf andere Sprachen beziehst, nur Sprachen mit C-Syntax bedenkst, zumal der GM doch immer noch ein Hybrid aus C und Pascal ist.

      DragonGamer schrieb:

      Übrigens
      !0.499 wird auch als "wahr" angesehen denn der GM verstehet alles < 0.5 als false und alles andere (inklusive 0.5) als true.
      Also sollte man da wirklich aufpassen..


      Ach verdammt! Das bringe ich doch jedes Mal wieder durcheinander... -.-
      Danke.