Programmierung

Wir zeigen Dir, wie's geht!

Was ist der Unterschied zwischen define und declare? Und was ist eigentlich eine Prozedur?

Mit dem Kommando define kannst Du global gültige Funktionen erzeugen, die dann wie jede andere Funktion in NumeRe verwendbar ist. Dabei kannst Du aber keine bereits vordefinierten Funktionen überschreiben, jedoch darauf referenzieren. Was ist eine Funktion, fragst Du? Eine Funktion ist ein mathematischer Ausdruck, der die Argumente eindeutig auf seine Werte abbildet und durch einen einzigen Ausdruck in NumeRe darstellbar ist. Sie werden in NumeRe durch ihren Namen und ihre Argumentklammern dargestellt, z.B. sin(x), arctan(x), norm(x,y,z,...)

Das Kommando declare verwendest Du, um in Deinem Code Konstanten zu definieren, die Du wiederholt verwenden willst oder die durch ihren Wert nicht auf ihre Verwendung hindeuten. Durch die Verwendung von benamten Konstanten wird Dein Code nämlich deutlich wart- und lesbarer. Im Unterschied zu define gelten die Konstanten, die declare anlegt, nur für die aktuelle Datei. Richtig globale Konstanten kannst Du also nur als Funktion mit null Argumenten definieren.

Prozeduren hingegen, die durch einen procedure $NAME(ARGS) ... endprocedure-Block dargestellt werden, können deutlich mehr erledigen, als es die Funktionen von define können. Prozeduren können global und auf die aktuelle Datei beschränkt implementiert werden. Du kannst sie verwenden, wenn Du herausforderndere Themen behandeln willst, so wie z.B. das Entwickeln einer Applikation oder eines Plugins. Prozeduren können die vielfältigsten Werte berechnen oder auch auf die ursprünglichen Argumente einwirken. Du kannst sie jedoch nicht als Plot- oder Fitfunktion verwenden.

Wie mache ich meinen Code lesbarer?

Lesbarer Code ist im Prinzip ein recht subjektives Thema. Manchen gefällt CamelCase anderen eher snake_case für ihre Variablen. Dann gibt es wieder solche, die ihre Variablen typisieren (d.h. ihnen Zeichen vorneanstellen, die den Typ ausdrücken sollen, z.B. nInteger oder fFloat) und solche, die das strikt ablehnen. Tatsächlich verleitet das vorneanstellen von Variablentypen dazu, diese mit nicht besonders sprechenden Namen zu versehen. Dabei sind sprechende Namen bei den Variablen das A und O guten Codes.

Was kannst Du nun konkret tun, um Deinen Code "für die breite Masse" lesbar zu gestalten? Wir können Dir die folgenden Tipps geben:

  • Verwende sprechende Variablennamen. Wir beobachten gelegentlich, dass Variablennamen a, b oder c lauten. Für jemanden, der den Code aber zum ersten Mal liest, sind diese Namen aber nicht hilfreich. Besser ist es, Variablennamen nach ihrem Inhalt zu bezeichnen, wie z.B. fAmplitude, fPhase oder nFieldCount

  • Begrenze die Zeilenlänge. Natürlich kann man vieles in eine Zeile schreiben, aber dadurch wird die Struktur nicht besser. Du kannst die Zeichensequenz \\ verwenden, um eine Zeile an dieser Stelle umzubrechen und in der nächsten Zeile fortzufahren. Wenn Du die Wahl hast, dann breche vor Operatoren um, so dass fortgesetzte Zeilen mit einem Operator beginnen und die Fortsetzung einfacher zu erkennen ist. Als eine gute Richtlinie bieten sich Zeilenumbrüche ab ca. 100 Zeichen an.

  • Verwende keine obskuren Literalkonstanten. Was ist eine Literalkonstante, fragst Du? Das ist eine Zahl oder eine Zeichenkette, die so direkt im Code auftaucht und nicht Teil einer Variablenzuweisung ist, z.B. ist in strfnd("myliteral", sInputLine) das erste Argument eine Literalkonstante. Warum ist das doof, fragst Du? Nun, speziell bei Zahlen kann man sich selten den Sinn dieser Zahl alleine aus ihrem Wert erschließen, was das Verständnis des Codes ungemein erschwert. Taucht z.B. im Code 21 als Literalkonstante auf, kannst Du damit sicher nicht viel anfangen. Steht da aber halfMeaningOfLife ist eher klar, was 21 bedeuten soll. Aber auch aus einem anderen Grund sind Literalkonstanten ein Problem: stellt man fest, dass die Konstante falsch war, darf man sie mühsam im gesamten Code suchen. Variablenwerte kann man dagegen komfortabel an einer einzigen Stelle ändern. Variablen-Konstanten müllen Dir den Workspace zu, sagst Du? Das ist korrekt und lösbar mit dem declare Kommando, das eine Konstante für die aktuelle Datei anlegt.

  • Verwende das Autoformatierungs-Feature. Natürlich braucht Dein Code keine Leerzeichen, um ausführbar zu sein. Dem Leser kann es aber ungemein helfen, wenn ein paar Leerzeichen (und -zeilen) die Struktur des Codes hervorheben. Du kannst das manuell machen, oder aber Du verwendest das Feature im Werkzeuge-Menü bzw. mittels CTRL-SHIFT-F

Wie schreibe ich eine Prozedur, die mein Problem löst?

Eine generisch gültige Antwort auf diese Frage können wir sicher nicht geben. Wenn das möglich wäre, gäbe es keine Probleme mehr, die wir lösen müssten. Wir können aber ein Beispiel zeigen, das die wesentlichen Elemente einer Prozedur erläutert und ihre Struktur aufzeigt. Als Problem wählen wir das recht einfache Schreiben von Logging-Nachrichten in eine Datei (eine vollständige Lösung gibt es auch bei den File tools).

Als ersten Schritt benötigen wir, da diese Prozedur global aufrufbar sein soll, eine neue Prozedurdatei, die denselben Namen wie die Prozedur tragen muss. In diesem Beispiel nennen wir die Prozedur $logger(), also erzeugen wir eine logger.nprc im Prozedurpfad (das geht auch komfortabel mit den entsprechenden Funktionen im Dateimenü). Normalerweise würde man hierfür noch den passenden Namespace auswählen, wir verwenden aber in diesem Beispiel den Hauptnamensraum.

Wenn wir die Prozedurdatei mit der entsprechenden Menüoption angelegt haben, ist der Prozedurrumpf bereits in der Datei zu finden. Anderenfalls schreiben wir

procedure $logger()

endprocedure

in die Datei. Damit haben wir die Prozedur angelegt und können sie nach dem Speichern bereits in der Konsole via $logger() aurufen, wobei das Ergebnis 1 (also true) sein muss. Das ist der Standardrückgabewert jeder Prozedur. Wir brauchen aber keinen Rückgabewert in unserem Fall, also fügen wir zwischen den beiden Zeilen die Zeile return void; ein (wenn bereits return true; in der Datei steht, tauschen wir das einfach aus).

Nun müssen wir uns Gedanken zu den Argumenten machen. Wir sehen drei vor: der Zieldateiname, die eigentliche Nachricht und das Logging-Level. Damit modifizieren wir die erste Zeile wie folgt: procedure $logger(_sFileName, _sMessage, _sLevel). Die Unterstriche sind nicht zwingend nötig. Sie dienen nur dazu die Argumente eindeutig zu identifizieren.

Wir wollen, dass das Logging-Level in Großbuchstaben erscheint, folglich transformieren wir es via _sLevel = to_uppercase(_sLevel);. Außerdem möchten wir, dass die aktuelle Zeit vor Logging-Level und der Nachricht auftaucht, also schreiben wir

_sMessage = timeformat("YYYY-MM-DD HH:mm:ss", time()) + " " + _sLevel + ": " + _sMessage;

Das Plus in dem Ausdruck verknüpft dabei die verschiedenen Zeichenketten zu einer einzigen. Jetzt müssen wir eigentlich nur noch die Nachricht in die Zieldatei schreiben. Vorher wollen wir aber, dass die Logging-Level "ERROR" und "WARN" als Warnung auf die Konsole geschrieben werden. Das erreichen wir durch das Einfügen des folgenden Blocks

if (_sLevel == "ERROR" || _sLevel == "WARN")

warn _sMessage;

endif

vor dem return void; Statement. Nun fügen wir direkt danach noch das Kommando write mit der Nachricht, dem Dateinamen und dem mode=app ein und unsere Prozedur ist fertig, wobeo natürlich ein paar Kommentare zu dem, was wir getan haben, sicher nicht falsch sind.

Fortsetzung folgt ...