Pseudocode

Um Algorithmen zu skizzieren, Ideen aufzuzeigen u.ä. eignet sich insbesondere Pseudocode. Zumindest für alles unterhalb der Klassenebene. Sind mehrere Klassen beteiligt, eignen sich grafische Notationen wie UML meist besser, aber ansonsten ist Pseudocode toll. Vor allem ist toll, dass man den Detailgrad beliebig variieren kann. Von fast kompilierfähig bis „abstrakte Codekunst“ ist so gut wie alles möglich. Außerdem bietet es die Möglichkeit, programmiersprachenunabhängig zu bleiben.

Für dieses Blog habe ich mich entschieden, meinen Pseudocode etwas zu „standardisieren“. Der Nachteil von Pseudocode ist ja, dass er überall anders aussieht, was der allgemeinen Verständlichkeit wieder etwas abträglich ist. Oberstes Ziel bei „meinem“ Pseudocode soll die Lesbarkeit sein. Schon bisher habe ich „pascalartigen Pseudocode“ verwendet, weil dieser relativ gut lesbar ist.

Folgendermaßen werde ich also ab jetzt meinen Pseudocode schreiben:

  • Es gibt keine Trennung zwischen Interface- und Implementation-Abschnitten wie bei Delphi
  • Klassen sind wie Methoden aufgebaut, d.h. sie haben einen separaten Teil für Variablen (und Konstanten, Invarianten, etc.)
  • Sichtbarkeitsmodifizierer u.ä. stehen bei jedem Feld und jeder Methode und nicht nur einmal
  • zu jedem begin gibts ein end und umgekehrt
  • das end wird mit dem block-spezifizierenden Schlüsselwort qualifiziert
  • extends und implements wie bei Java machen Vererbung lesbarer
  • inherited statt super
  • self statt this
  • method statt procedure bzw. function
  • procedure und function definieren klassenunabhängige Prozeduren
  • = und := wie in Pascal
  • Doppelte Anführungszeichen für String, einfache für Chars
  • Leere Parameterklammern werden bei Methoden immer angegeben und können nicht ausgelassen werden (wie bei Java, u.ä.)
  • and, or, xor für logische und binär-Operatoren
  • catch statt except, null statt nil und != statt <>
  • preconditions-, postconditions– und invariants-Abschnitte bieten die Möglichkeit für DBC. Für jemanden, der sowas noch nicht gesehen hat, ist das vermutlich lesbarer als requires und ensures, denke ich
  • return (wie in C/C++, Java, etc.) und result (wie in Delphi) gibt es beides, wobei return die Methode verlässt.
  • Das zusätzliche Einfügen von new vor dem Konstruktoraufruf soll auch Delphi-Unkundigen verdeutlichen, was hier passiert.
  • if-Anweisungen haben entweder einen Bock (mit begin), der ggf. durch else if und else aufgeteilt sein kann oder keinen Block, dann gibt es aber auch keine Blöcke für else-Fälle. Eventuelle Mehrdeutigkeiten werden durch eindeutige Einrückungen unterschieden.
  • switch-Anweisung ähnlich wie in C++/Java/etc. Ohne break; wäre es zwar besser lesbar, würde aber wohl Leute verwirren, die so eines erwarten, also mit break in case und er Möglichkeit des Fall-Through.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
function foobar(): Integer;
begin
  return 42;
end function;

procedure blubb();
begin
  nop;
end procedure;

class Subclass extends Baseclass implements ISomeInterface, IAnotherInterface
const
  private KONSTANTE = 21;
var
  private FMyVariable: Integer = 42;
  private FMyString: String = "";
invariants // optional DBC
  FMyVariable > 0;
begin

  public constructor create(AParameter: String);
  begin
    inherited Create;
    FMyString := AParameter;
    doSth();
  end constructor;

  public method doSth(AParam: Integer = 42): Void; // ":Void" optional
  var
    a: Integer;
    b: Integer;
    p: pointer to Integer;
    arr: array of String;
  preconditions // optional DBC
    AParam > 0;
  postconditions // optional DBC
    self.FMyVariable > old self.FMyVariable;
  invariants // optional DBC
    p != null;
  begin
    a := readln().toInt();
    b := readln().toInt();

    // if mit Block
    if a > b then
    begin
      a := 42;
      showMessage("a");
    else if a = 0 then
      b := 12;
    else
      showMessahe("im else-Zweig");
    end if;

    // if ohne Block:
    if isThursday then bad(); else good();
  end method;

  internal static virtual synchronized method foobar(); // ähnlich Java/C#
  begin
    switch(x)
    begin
      case 0..10:
        doSth();
        break;
      case 11..20:
        doNothing();
        break;
      default: assert(false);
    end switch;

    for each i in 0..100 do
    begin
      writeln(i);
    end for each;
  end method;

  public static method main(AArgs: array of string): Void; // Programmeinsprungspunkt
  var
    obj: Subclass;
  begin
    obj := new Subclass.create("Foobar");
    try
    begin
      obj.doSth();
    catch(e: ESomeException)
      writeln(e);
    finally
      obj.free();
    end try;
  end method;

end class;

Das ist keine formale Definition und das soll sie auch gar nicht sein. Ziel ist ja immer noch, Pseudocode zu schreiben, also nur eine Idee zu skizzieren.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.