Ein paar Worte vorabHome   Letzte MeldungenNews   Index der Kapitel und der besprochenen FunktionenIndex   Wer ich bin, warum ich diese Seiten mache, KontaktImpressum   Ich freue mich über jeden Eintrag im Gästebuch!Gästebuch   Einige Links zu anderen AutoLisp-SeitenLinks   Copyrights und DisclaimerRechts
Hier können die kompletten Seiten als ZIP-File heruntergeladen werden!

Berechnen von arithmetischen Ausdrücken in der Kommandozeile Sitz!Platz!Fass!
Das Verschachteln von Ausdrücken Alte Schachtel!
Das Speichern von Werten in Variablen Gebunkert
Verhindern der Evaluation mit Quote Bergbäche
Erzeugen von einfachen Listen in AutoLisp Brot,Eier,Käse
Einfache Funktionen zur Listenbearbeitung ...um die Wurst
Funktionen für den Zugriff auf Listenelemente Was ein Salat!
Über Haupt- und Nebeneffekte von Funktionen Schwer schuften
Das Definieren von eigenen Funktionen in AutoLisp Ostfriesischer...
Lokale Variablen und Funktionsargumente in AutoLisp Kondome!
Das Laden von Programmdateien in AutoLisp Banküberfall
Verzweigung in Funktionen aufgrund von Entscheidungen Wenn das Wort...
Zusammenfassen von Entscheidungen mit den Logik-Funktionen Ins Schweinderl
Mehrfach-Verzweigungen in AutoLisp mit Cond 3. Strasse links
Schleifen zum Steuern des Ablaufs in AutoLisp-Funktionen Wie im Fernsehen
Testfunktionen zum Steuern von Schleifen in AutoLisp Schwanger?
Gleichheitstests als Schleifenkriterium in AutoLisp Noch gleicher?
Zeichneketten-Bearbeitung in AutoLisp Rauchzeichen
Funktionen zur Konvertierung von Datentypen in AutoLisp Wasser zu Wein
Komplexere Funktionen für die Bearbeitung von Listen in AutoLisp Nicht arbeiten...
Das Erzeugen von anonymen Funktionen mit lambda Schwarze Kutte
Das Bearbeiten von Listenelementen mit foreach Jedem das Seine
Erzeugen und Verwenden von Assoziationslisten in AutoLisp Beim Psychiater
Zugriff auf Geometriedaten und Erzeugen von Geometrieelementen Ententanz
Der Umgang mit Auswahlsätzen in AutoLisp Jung gefreit, ...
Auswahl von AutoCAD-Zeichnungsgeometrie mit ssget Raffgierig!
Verändern von Zeichnungs-Geometrie mit entmod Flickschusterei
Das Erzeugen von Geometrie mit entmake Houdini
Über Programmierstile in AutoLisp, Teil 1 Emma
Über Programmierstile in AutoLisp, Teil 2 Sti(e)lblüten
Über Programmierstile in AutoLisp, Teil 3 Eingewickelt
Über Programmierstile in AutoLisp, Teil 4 Doofe Frisur?


Zum den Seiten für Fortgeschrittene

Zu den ActiveX-Seiten

Meine Private HP mit Fotos, Gedichten, Musik und Postkartenversand

Mein Online-Lexikon der Fotografie

Mein völlig abgedrehtes Reisebüro










In den folgenden Kapiteln soll es um das Formale gehen: Stilfragen. Da es über dieses Thema eine Menge zu sagen gibt, wird sich das Thema über mehrere Kapitel erstrecken - ich möchte vermeiden, dass hier ein Monsterkapitel entsteht, während ich mich gleichzeitig über Monsterfunktionen in Lisp lustigmache.

Wenn man sich die im Internet kursierenden AutoLisp-Programme (es gibt ja eine riesige Menge an Public-Doman-Programmen) einmal näher anschaut, dann fallen dem geübten Auge einige Dinge auf:
  1. Das setq-Syndrom
    An erster Stelle steht sicherlich die Marotte, jeden einzelnen Zwischenschritt in den Funktionen mit Hilfe von (setq) irgendwelchen Variablen zuzuweisen, die aber fast immer nur in der nächsten Zeile wieder ausgelesen werden, um den Programmfaden weiter zu spinnen. Die Variablen werden nie wieder gebraucht und sind daher schlicht und einfach überflüssig. Oft werden sie dann auch nicht einmal lokal deklariert, was vermutlich auf ihre immense Anzahl zurückzuführen ist.

  2. Funktions-Monster
    Als zweites wird man oft erschlagen von irgendwelchen Monsterfunktionen, die zwar möglicherweise vieles erledigen, und das durchaus auch noch mehr oder weniger korrekt, aber diese Funktionen sind völlig unhandlich. Es lässt sich weder sagen, was sie wirklich tun, noch haben sie eine irgendwie definierte Rückgabe. Die Autoren solcher Funktionen erfinden das Rad ständig neu: Bei einer fast identischen Aufgabenstellung lassen sich einzelne Funktionen nicht wiederverwenden, da eine saubere Trennung zwischen den einzelnen Aufgaben bzw. zwischen den Einzellösungen nicht gegeben ist.

  3. Stilblüten
    Dann sind oft Konstruktionen zu bewundern, bei denen mir nur eines einfällt: Das nette Büchlein 'Was blüht denn da?' aus dem Kosmos-Verlag. Natürlich sind solche Stilblüten im Schwierigkeitsgrad des Erkennens abgestuft - aber viele davon sind so offensichtlich, dass man sich wirklich über die enorme Hartnäckigkeit wundern muss, mit der sie sich wie Schimmelpilze in den AutoLisp-Programmen dieser Welt verbreiten.

  4. pretty printing Ein weiteres Handicap, das AutoLisp-Programmierer der Lesbarkeit ihrer Programme mitgeben, ist der beim Einrücken angewendete Stil. Alle sind sich einig, dass Programme, die überhaupt nicht eingerückt sind, mehr oder weniger völlig unleserlich sind. Also rücken alle ein - aber sind denn Programme, bei denen die Zeilen völlig willkürlich mal links, mal rechts um eine zufällige Anzahl von Spalten verschoben wurden, in irgendeiner Weise lesbarer?

  5. Kommentare
    Auch das Ausstatten von Programmen mit Kommentaren erweckt oft den Anschein, als sei man hier mit wenig Sachverstand an die Sache gegangen: Schlimmer noch als ein völlig unkommentiertes Programm ist eines, in dem man vor lauter (überflüssigen) Kommentaren die (oft wenigen) Codezeilen mit der Lupe suchen muss. Sinn und Zweck von Kommentaren ist nicht, das Offensichtliche nachzuplappern, sondern Hinweise auf das zu geben, was sich einem ersten Blick entzieht. Nur wenige Programme erreichen hier das Klassenziel.

  6. Namensvergabe
    Mit dem letzten Punkt hängt die Art und Weise der Namensvergabe für Funktionen und Variablen sehr eng zusammen. Deskriptive (d.h. beschreibende, aussagefähige, selbsterklärende) Namen machen eine Menge von Kommentaren von vornherein überflüssig, da die Lesbarkeit des Programmcodes selbst zunimmt.

  7. Überkandidelt
    Und dann gibt es auch den superstraffen Code, der auf den ersten Blick sehr effektiv wirkt - der es aber nicht ist. Der Verzicht auf Variablenzuweisungen ist gut und schön, aber nur dann, wenn er sinnvoll ist. Wenn in einer Schleife zehntausendmal die Zahl Pi durch Vier geteilt wird, dann ist einfach davon auszugehen, dass zehntausendmal das selbe Ergebnis dabei herauskommt. Auch wenn die Prozessoren immer billiger werden: Muss man das arme Ding denn so quälen?
Zunächst einmal möchte ich noch kurz darauf eingehen, was ich für die Ursachen dieser hier angesprochenen Mängel halte. Im ersten Fall scheint mir das offensichtlich: Leute, die mit AutoLisp programmieren, sind meist keine Informatiker, sondern Zeichner, Ingenieure, Architekten, die irgendwann begriffen haben, dass man sich durch das Automatisieren bestimmter Abläufe in AutoCAD das Leben enorm erleichtern kann.

In vielen Fällen war dann AutoLisp auch die erste Programmiersprache überhaupt, mit der man zu tun hatte. Die Hilfen zu AutoLisp, die man mit einer AutoCAD-Lizenz erwirbt, tragen ihren Teil zu dem Drama bei: Die Funktionen werden einzeln ohne jede Gewichtung beschrieben, Zusammenhänge und Konzepte werden aber kaum vermittelt. Kein Wunder also, wenn die Einsteiger oft auf dem untersten Level stehenbleiben und die geschriebenen Programme genau das widerspiegeln, was in den Hilfen vermittelt wird: Zerstückelung.

Ein Problem übrigens, an dem nicht nur die Online-Hilfe von AutoCAD leidet, sondern alle neuzeitlichen Online-Hilfen ebenso: Es können, da die Struktur automatisch generiert wird, nur noch Fragmente nebeneinander gestellt werden. Einen roten Faden kann es in solchen Hilfen nicht mehr geben!

Oft wird von AutoLisp-Einsteigern das Argument angebracht, dass ihnen die tiefe Verschachtelung 'zu viel', 'zu hoch', 'zu kompliziert' sei und dass dies der Grund dafür sei, dass man sich mit den vielen (setq ...)-Anweisungen behelfe, um die Aufgabenstellung in kleine Häppchen einzuteilen. Es gibt aber ein gutes Argument dagegen: Statt sich innerhalb einer Funktion mit (setq) solche geistigen Rastplätze zu bauen, sollte man genau dieses Konzept gleich richtig anwenden: Modularisieren!

Damit sind wir beim zweiten Punkt angekommen: Es ist doch völlig legitim, dass man sich diese Ruhebänkchen schaffen möchte! Eine komplexe Aufgabe sollte man unbedingt in einfachere Teilschritte zerlegen - aber nicht, indem man Zwischenergebnisse in Variablen abspeichert, die niemand braucht und die nie wieder ausgelesen werden. Lieber sollte man sich Folgendes zu Herzen nehmen: Eine Funktion sollte immer nur einen einzigen Zweck erfüllen, und sie sollte einfach kurz sein.

Ich möchte mich hier nicht der Meinung anschliessen, dass eine Funktion nicht mehr als fünf Zeilen haben sollte, da ich denke, dass dies ein praxisfremder Wert ist. Aber wie wär's mit 10? Gezählt werden hier allerdings nur die eigentlichen Code-Zeilen, d.h. die Zeilen, die nur schliessende Klammern enthalten, rechnen wir einfach nicht mit.

Blödsinn? Nein, so kann man das nicht sehen: Ein vernünftiges Programm kann durchaus so aussehen:
(defun c:mach-was( / )
  (error-handling-start ...)
  (zeichne(lesen "datei")...)
  (error-handling-ende)
  (princ)
)
                  
Vielleicht ist ja doch was dran an der Fünf-Zeilen-Theorie? Natürlich ist da nicht alles drin - aber genau das ist ja das Prinzip des Modularisierens. Die Funktion (lesen) könnte vielleicht so aussehen:
(defun lesen(datei-name / handle rueckgabe)
  (if(setq handle(open datei-name "r"))
    (progn
      (setq rueckgabe(datei-lesen handle))
      (close handle)
    )
  )
  rueckgabe
)
                  
Ja, diese Funktion hat schon sechs Code-Zeilen, aber sie könnte auch nur vier haben, wenn man die (progn)-Anweisung in einer Zeile zusammfassen würde. Trotzdem könnte hier vielleicht das Gefühl entstehen, dass wir Dinge vor uns herschieben: Der bisherige Code delegiert nur Aufgaben, aber er zeichnet bisher nicht einen einzigen Strich, und er macht zwar eine Datei auf und zu, aber daraus lesen tut er auch noch nicht.

Nein, wir wollen doch gar nicht die Dinge vor uns herschieben. Wir wollen doch nur, dass jede Funktion genau einen Zweck erfüllt und möglichst kurz und übersichtlich ist, um uns damit die gedanklichen Rastplätze zu schaffen. Wichtig ist nur, den Code so zu strukturieren, dass a) keine auch noch so kleine Aufgabenstellung zweimal gelöst werden muss, und b) möglichst viele der einzelnen Funktionen vom Zusammenhang losgelöst wiederverwendet werden können.

In unserem Beispiel-Fragment bedeutet das z.B., dass man den Komplex 'Lesen' aus der Hauptfunktion herausnimmt - da gehört er nämlich nicht hinein. Das Hauptprogramm ist nur dafür zuständig, die einzelnen Aufgaben an die entsprechenden Module zu delegieren. Dies macht deshalb so viel Sinn, weil dann die Möglichkeit besteht, einzelne Module auszutauschen - ohne eine Änderung im Hauptprogramm kann z.B. gewechselt werden zwischen einem Lesen aus einer Datei, Eingabe durch den Benutzer, Auswertung von in der Zeichnung gespeicherten Informationen.

Ganz konkrete Beispiele für eine Vermischung von Aufgabenstellungen und daraus resultierendem Ansatz zum Funktionsmonster können z.B. sein:
  • Vermischung von übergeordneten Aufgaben und kleinen Pfriemeleien auf unterster Ebene. Als Beispiel: Funktionen wie (substr) haben in einer Top-Level-Funktion (z.B. denen, die mit C: als AutoCAD-Befehle erzeugt werden, absolut nichts zu suchen!

  • Vermischen von verschiedenen Aufgaben. Als Beispiel kann man sich z.B. eine Funktion vorstellen, in der eine Benutzeranfrage (z.B. Auswahl einer Polylinie) mit Geometrie-Datenbankaufgaben sowie geometrischen Berechnungen (z.B. Berechnen des Krümmungsradius eines Segments über den 'bulge') durcheinandergewürfelt werden. Denken wir doch mal an die Einführung der LW-Polylinie zurück: Bei solchen Mischfunktionen war es nicht möglich, einfach eine neue Funktion zum Auslesen der Stützpunkte nachzuschieben - in vielen Fällen musste das ganze Programm neu geschrieben werden, da eine Entmischung gar nicht mehr möglich war!

  • Vermischung des 'Was' und des 'Wie'. Nehmen wir einmal an, es geht darum, ein paar Informationen in der Zeichnung abzuspeichern. Der falsche Weg ist auf jeden Fall, schon in der Top-Level-Funktion mit (regapp) anzufangen, weil man sich entschlossen hat, die Daten als XDATA abzulegen. Jede weitere Funktion speichert oder liest auch noch ein paar XDaten - dafür bekommen wir die Quittung, dass so ein Programm nachträglich kaum noch auf das Speichern in einem Dictionary umstellbar ist.

  • Lesen aus einer Datei, während gleichzeitig am Bildschirm gezeichnet wird - vielleicht wollen wir ja nächstes Jahr das gleiche zeichnen, aber direkt aus dem Internet lesen?
Diese Liste enthält nur ein paar Beispiele - sie ist auf keinen Fall als vollständig anzusehen. Zu den Punkten 1 und 2 der am Anfang dargestellten Liste habe ich ein paar Dinge gesagt. Ein guter Anlass, noch einmal das Wichtigste zum setq-Syndrom und den Monsterfunktionen zusammenzufassen:
    Versuchen Sie nicht, über ein Speichern von Zwischenwerten in Variablen gedankliche 'Breakpoints' in Funktionen einzubringen (nach dem Motto: 'Bis hier klappt's jetzt alles, jetzt fange ich was neues an!). Genau da, wo Sie anfangen, solche Überlegungen anzustellen, ist nämlich Ihre Funktion zu Ende - machen Sie das (defun) zu und fangen Sie eine neue Funktion für die neue Aufgabe an!

  • Vermischen Sie niemals hochrangige Aufgaben mit den lästigen Kleinigkeiten - die gesamte Zeichenkettenverarbeitung z.B. sollte in irgendwelchen Hilfsfunktionen und -dateien verschwinden und in den wesentlichen Teilen des Codes völlig unsichtbar sein!

  • Vermischen Sie ebensowenig unterschiedliche Aufgaben miteinander! Trennen Sie Beispielsweise den DCL-Teil eines Programms völlig ab, dann können Sie sich später immer noch überlegen, z.B. ObjectDCL oder eine ähnlich Bibliothek zu benutzen, ohne das ganze Programm neu schreiben zu müssen. Trennen Sie die Eingabe von der Ausgabe, lagern Sie alle Berechnungen in Module aus (diese Berechnungen können Sie ganz bestimmt auch noch woanders gebrauchen) usw. usf.

  • Legen Sie sich nicht vorzeitig auf bestimmte Techniken fest - d.h., machen Sie nicht in der Hauptfunktion schon die Input-Datei auf. Nennen Sie den Vorgang zunächst einmal 'daten-holen' und kümmern Sie sich später darum, woher die Daten kommen und wie sie geholt werden!

  • Lösen Sie kein Problem zweimal! Wenn in Ihrem Code die gleichen Formulierungen mehrfach vorkommen, dann machen Sie irgendetwas falsch!
  • Im nächsten Kapitel werden wir uns mit den 'Stilblüten' befassen, im übernächsten geht es um das Einrücken und Kommentieren von Programmen, und dann folgt ein weiteres, in dem wir ein Programm in zwei Varianten behandeln. Sie ahnen es schon: Ein abschreckendes Beispiel und - als Gegenüberstellung - ein funktionelles und ordentliches Programm.


    Übungsaufgaben

    1. Sagen wir einfach mal: Hitzefrei!
      Zu diesem Kapitel gibt es keine Übungsaufgaben.