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










Im vorigen Kapitel haben wir uns schon mit einigen Stilfragen befasst, z.B. mit dem offensichtlich stark verbreiteten Drang, alles Mögliche mit (setq) irgendwelchen Variablen zuzuweisen, die keiner braucht und die auch nie wieder abgefragt werden. Und wer schön aufgepasst hat, wird auch nie wieder ganz verschiedene Aufgabenstellungen in unschuldigen Funktionen vermischen... Versprochen?

In diesem Kapitel soll es um Stilblüten gehen - Codeschnipsel, die absolut nichts bringen, aber vielleicht dem Prozessor das Leben ein wenig schwerer machen. Wahrscheinlich erschweren sie auch das Lesen eines Programms! Solche Stilblüten entstehen fast immer aus mangelndem Wissen um Einzelheiten. Manchmal ist auch Unsicherheit im Spiel - man vertraut einfach bestimmten Mechanismen nicht.

Viele solcher Stilblüten entstehen, weil Unklarheiten darüber bestehen, was nil und T sind. Werfen wir doch mal einen Blick darauf: T ist NICHT das Gegenteil von nil, das ist zunächst einmal die wesentliche Aussage! Was wir wissen müssen: AutoLisp kennt keine sog. Booleschen Variablen, also solche Variablen, die per Deklaration nur die beiden Zustände 'wahr' oder 'falsch' annehmen können.

Die Regel ist einfach: Alles, was zu nil evaluiert, ist falsch oder unwahr. Natürlich hat das wenig damit zu tun, was im realen Leben der Fall ist - aber dazu noch einmal etwas weiter unten. Eines ist auf jeden Fall falsch bzw. unwahr: der Umkehrschluss, dass alles, was wahr ist, auch T ist (wobei T für das englische Wort true steht).

Die Gegenregel ist genauso einfach: Alles, was nicht zu nil evaluiert, ist wahr! Noch einmal: Es geht hier nicht um eine exakte Abbildung der Realität - es geht nur um eine Vereinbarung! Mit 'wahr' und 'falsch' beschreiben wir einfach zwei Zustände, damit wir sie voneinander unterscheiden können - sonst nichts.

In der englischen Sprache liegen die Dinge einfach: nil, was übrigens die Abkürzung für 'not-in-list' oder auch 'nothing-in-list' ist, kann man mit 'nothing' umschreiben. Andere Programmiersprachen kennen 'nothing' durchaus als Schlüsselwort für leere Listen, nicht-initialisierte Variablen und dergleichen. Das Gegenteil ist 'anything' - genau das wird vom AutoLisp-Interpreter als 'wahr' eingestuft. Auf deutsch: 'Etwas', 'irgendwas' ... Mir persönlich gefällt da das 'Ichts' am besten - ok, ok, nie gehört. Scheint ein etwas untergegangenes Wort zu sein (s. dazu de.rec.sprache.deutsch am 21.6.2002). Trotzdem bleibe ich dabei: nil ist das Nichts, alles andere ist das Ichts.

Und was hat nun T damit zu tun? T ist ein Symbol, nichts weiter. Es gibt aber eine Art Vereinbarung, dass Funktionen das Symbol T zurückgeben, wenn inhaltlich ein true gemeint ist. Was würde sich ändern, wenn alle Funktionen, die bisher im Wahr-Fall T zurückgeben, ab morgen X oder SCHOENES-WETTER-HEUTE zurückgäben? Nichts! Entweder gibt eine Funktion nil zurück, dann wissen wir, dass es der Falsch-/Unwahr-/Nichts-Fall war, oder sie gibt etwas anderes zurück - dann war es der Wahr-/Richtig/Ichts-Fall. Aber was die Funktion im Einzelnen zurückgibt, spielt keinerlei Rolle. Und damit kommen wir zur AutoLisp-Stilblüte schlechthin:
(if (/= irgendeine-liste nil)
  (dann-mach-weiter ...)
  (dann-lass-stecken ...)
)
                  
Wer die Anfangskapitel dieses Tutorials aufmerksam gelesen hat, kennt die Regeln: Die Argumente werden von links nach rechts verarbeitet, also ist die Klammer mit der Funktion (/= ...) zuerst dran. irgendeine-liste evaluiert dann zu nil, wenn die Liste leer ist. Was testen wir dann? Es wird getestet, ob nil ungleich nil ist. Das kann auf jden Fall nur 'wahr' ergeben.

Wesentlich ist hier das Wissen, dass irgendeine-liste sowieso zu 'wahr' evaluiert, wenn sie nicht leer ist. Also warum nicht gleich so:
(if irgendeine-liste
  (dann-mach-weiter ...)
  (dann-lass-stecken ...)
)
                  
Mehr ist nicht nötig - alles andere bremst nur und macht den Code unleserlich! Eine ähnliche Unsauberkeit ist die Rückgabe eines expliziten nil, wenn sowieso schon nil zurückgegeben wird. Sehen wir uns ein Beispiel an:
(defun teste-was(daten / ergebnis)
  (setq ergebnis(machwas-mit daten))
  (if(/= ergebnis nil)
    ergebnis
    nil
  )
)
                  
Auch hier werden unsinnige Vergleiche durchgeführt. Entweder enthält ergebnis etwas ('wahr') oder nicht (nil). Statt der ganzen (if ...)-Konstruktion können wir also einfach ergebnis hinschreiben, ohne dass sich etwas ändert:
(defun teste-was(daten / ergebnis)
  (setq ergebnis(machwas-mit daten))
  ergebnis
)
                  
Aber auch das ist noch zu viel! Die Rückgabe von (setq) ist doch identisch mit der Rückgabe von ergebnis. Es kann also weiter gekürzt werden:
(defun teste-was(daten / ergebnis)
  (setq ergebnis(machwas-mit daten))
)
                  
Die Funktion wird unbeeindruckt weiterlaufen. Und nun natürlich die letzte Frage: Wozu eigentlich (setq)? Weg damit:
(defun teste-was(daten / )
  (machwas-mit daten)
)
                  
Auch diese vierte Version der Funktion verhält sich noch immer identisch zur ersten!

Nun noch einmal zum Symbol T und dem oft hilflos wirkenden Umgang damit. Wie bereits gesagt, ist T nicht das Gegenteil von nil. Es ist nur eine Konvention, dass Testfunktionen meistens das Symbol T zurückgeben, wenn 'wahr' angezeigt werden sollte. Wie immer, wenn wir mit Symbolen selbst arbeiten, aber nicht an evtl. daran gebundenen Werten interessiert sind, müssen wir T also mit einem Quote-Zeichen versehen, wenn wir es selbst verwenden. Als Beispiel eine kleine Funktion, in der mit Symbolen ohne Wertbindung gearbeitet wird:
(defun kategorien(zahl / )
  (cond
    ( (> zahl 10000)'riesengross)
    ( (> zahl 1000)'gross)
    ( (> zahl 100)'mittel)
    ('T 'klein) ; so ist's korrekt!
  )
)
                  
Hier wird das Symbol T korrekt verwendet - ohne das Quote-Hochkomma würde das Symbol nämlich evaluiert, was aber überhaupt nicht nötig oder erwünscht ist! Die neueren AutoCAD-Versionen leisten dieser Stilblüte nun auch noch Vorschub: das Symbol T ist nun geschützt, kann nicht mehr verändert werden und evaluiert zu sich selbst. Damit hat aber dieses Symbol nun einen Sonderstatus, der der Sache gar nicht entspricht: irgendeine Funktion hat T nach wie vor nicht, da die Booleschen Variablen ja keinen Datentyp darstellen.

Die einen werden sagen: Ist doch praktisch, jetzt kann da wenigstens nichts mehr passieren! Es ist aber all die Jahre nichts passiert, wenn man ordentlich gearbeitet hat - es war möglich, eine Variable trotzdem T zu nennen usw. Passiert ist nur eines: Wer exzessiv mit Symbolen arbeitet (z.B. als Assoziationsschlüssel für Listen), kann sich nicht mehr darauf verlassen, dass das problemlos läuft - irgendwo könnte ja ein Symbol entstehen, das zufällig T heisst, und dann bleibt das Programm eventuell mit einer Fehlermeldung stehen.

Eine weitere stark verbreitete Stilblüte ist das zuweisen von nil an Variablen, die sowieso nichts enthalten:
(defun eine-funktion(arg / var1 var2)
  (setq var1 '())
  (setq var2 nil)
  ...
  ...
)
                  
Die beiden Zeilen im Funktionsrumpf haben absolut keine Wirkung, sie vebrauchen nur einfach Rechenzeit. Und warum werden zwei verschiedene Erscheinungsformen von nil verwendet? Offensichtlich glaubte der Autor dieser Zeilen, dass die erste (setq)-Anweisung damit aus var1 eine leere Liste gemacht wird, aus var2 hingegen eine andere Variable. Das ist aber schlicht und einfach Unsinn! Jeder Datentyp in AutoLisp kann an jedes Symbol gebunden werden (mit Ausnahme von T neuerdings).

Machen wir die Dinge noch einmal klar: Jedes verwendete Symbol, dem bisher kein Wert zugewiesen wurde, ist an nil gebunden. Da aber eine leere Liste identisch mit nil ist, sind ungebundene Symbole de facto immer leere Listen! Technisch gesehen ist es aber so, dass es in AutoLisp überhaupt keine leeren Listen gibt - leere Listen sind nichts weiter als ein gedankliches Konzept, aber kein technisches!

Und nun zur letzten Stilblüte, die ich hier anführen möchte: Wenn es um die Rückgabe einer Funktion geht, sind manchmal akrobatische Code-Verrenkungen zu beobachten:
(defun noch-eine-funktion(daten / element ergebnis)
  (foreach element daten
    (setq ergebnis ....)
  )
  (reverse(reverse ergebnis))
)

; Die letzte Zeile könnte auch
; so lauten:
  (car(list ergebnis))

; oder so (habe ich auch
; schon gesehen):
  (append ergebnis)
                  
Darüber, dass hier element zusätzlich als lokale Variable deklariert wurde, obwohl die andere Variable element bereits zu foreach lokal ist, sehen wir einmal hinweg. Wesentlicher ist die Frage, warum ergebnis am Ende der Funktion zweimal umgedreht wird: Scheinbar wusste der Autor einfach nicht, wie man eine einfache Rückgabe aus einer Variablen erzeugt: Man lässt einfach den Variablennamen als Ausdruck evaluieren!
(defun noch-eine-funktion(daten / ergebnis)
  (foreach element daten
    (setq ergebnis ....)
  )
  ergebnis
)
                  
So sieht die Funktion also 'komplett bereinigt' aus. Natürlich gibt es noch eine ganze Menge mehr solcher unsinniger Konstruktionen - ich habe mich nur bemüht, ein paar besonders repräsentative Exemplare herauszugreifen.


Übungsaufgaben

Schauen Sie sich diese Funktion an. Finden Sie heraus, was Sie tut, kritisieren Sie sie, und schreiben Sie dann eine neue Version, die den gleichen Zweck erfüllt (lassen Sie aber das weg, was nicht hineingehört).
(defun abcde(zzz / liste elem pkt1 pkt2 pliste)
  (setq pliste nil)
  (setq elem zzz)
  (command "_UCS" "_W")
  (setq pkt1 (cdr (assoc 10 elem)))
  (setq pkt2 (cdr (assoc 11 elem)))
  (setq pliste (append pliste (list pkt1)))
  (setq pliste (append pliste (list pkt2)))
  (setq ppliste (append ppliste (list pliste)))
)
                  
Lösungen