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










Bisher haben wir nur einzelne Ausdrücke zum Evaluieren an AutoLISP geleitet. Wenn wir aber daran denken, richtige Programme zu schreiben, mit denen wir Problemstellungen in AutoCAD bearbeiten wollen, dann müssen die Programme
  • als neue (selbstdefinierte) Funktionen aufrufbar sein
  • in der Lage sein, auf unterschiedliche Situationen unterschiedlich zu reagieren
  • in Dateien abgelegt werden können
  • bei Bedarf aufrufbar sein
Was bringen uns Funktionen? Funktionen fassen Teile des Programmcodes zusammen und machen ihn mehrfach verwendbar. Wenn wir absehen können, dass ein bestimmter Ablauf mehrmals im Programm vorkommen wird, dann sollten wir eine Funktion dafür schreiben. Das erspart Schreibarbeit und auch Speicherplatz, da der entsprechende Code nur einmal im Speicher vorhanden ist und nicht mehrfach.

Ein weiterer Vorteil ist, dass die Anzahl der Variablen im Hauptprogramm sehr stark reduziert wird, da die meisten Variablen in den Funktionen verschwinden und dort lokal sind (dieser Begriff wird im Verlauf dieses Kapitels noch erläutert).

Im Laufe der Zeit wird man dann auch noch feststellen, dass es sehr nützlich sein kann, Funktionen anzulegen, die nicht mehr nur innerhalb eines Programms verwendet werden, sondern aus allen möglichen verschiedenen Programmen heraus aufgerufen werden können. Eine solche Sammlung von allgemein nutzbaren Funktionen bezeichnet man als Funktionsbibliothek.

Beginnen wir damit, unser bisher erarbeitetes Wissen als neue Funktionen im Speicher abzulegen und dadurch dafür zu sorgen, dass wir sie jederzeit wieder aufrufen und benutzen können. Die entsprechende AutoLISP-Funktion heisst (defun ...), was in etwa mit 'definiere Funktion' zu übersetzen ist. Sie ist eine von den Funktionen, die eine beliebige Anzahl von Argumenten erhalten können, das Minimum an Argumenten ist allerdings drei. Sie gehört aber auch zu der Gruppe von Funktionen, die Nebeneffekte haben. Ihre Rückgabe, der Haupteffekt, besteht lediglich aus dem Namen der definierten Funktion.

Die Anwendung von (defun ...) gleicht in dieser Hinsicht also der Anwendung von (set) und (setq), die wir ja auch wegen ihrer Nebeneffekte nutzen und den Haupteffekt meistens verpuffen lassen. Eine weitere Eigenschaft von (defun) ist, dass alle Argumente nicht evaluiert werden. Sie wie (setq) die Evaluation des ersten Argumentes verhindert, wird sie von (defun) bei allen Argumenten verhindert.

Das erste Argument von (defun) gibt den Namen der neuen Funktion an, d.h. das Symbol, an das der Funktionscode gebunden wird. Das zweite Argument von (defun) hat eine besondere Bedeutung und muss auf jeden Fall eine Liste sein. Diese Liste kann unter Umständen leer sein, sie muss aber immer übergeben werden. Diese Liste heisst in AutoLISP 'Formale Argumentenliste'. In ihr werden die Namen der Argumente für die neue Funktion eingetragen.

Ein Beispiel: Wir wollen eine Funktion schreiben, die eine Zahl quadriert. Der Name soll (sqr) sein. AutoLISP selbst stellt diese Funktion nicht zur Verfügung, quadrieren können wir also nur mit (* ...) und (expt ...). Unsere neue Funktion (sqr) hat also durchaus praktischen Nutzen. Das Argument für (sqr) nennen wir einfach zahl. Und so sieht die Funktionsdefinition aus:
(defun sqr (zahl) (* zahl zahl))
                  
Nachdem wir diesen Ausdruck eingegeben haben, können wir unsere neue Funktion gleich ausprobieren:
(sqr 8)          =>  64
(sqr -1)         =>  1
(sqr 1.5)        =>  2.25
                  
Das sieht doch schon sehr gut aus, nicht wahr? Wir machen noch einen Test, um festzustellen, ob die Funktion wirklich korrekt arbeitet. Die Überlegung bei diesem Test ist einfach die, daá sich Quadrieren und Wurzelziehen gegenseitig aufheben.
(sqr(sqrt 153.75))    -> 153.75
                  
Es überrscht nicht, dass unsere Funktion des Test bravourös besteht. Wir wollen jetzt etwas genauer untersuchen, wie der Aufruf von (defun) evaluiert wurde und was er bewirkte.

(defun) wurde mit drei Argumenten aufgerufen, also der minimal möglichen Anzahl von Argumenten. Keines der drei Argumente wurde quotiert, (defun) macht das automatisch für uns. Das erste Argument legte den Namen sqr für unsere neue Funktion fest. Das zweite Argument - die formale Argumentenliste - enthielt nur ein Element, nämlich das Symbol zahl. Das dritte Element stellte den Programmcode zur Verfügung, der hier sehr kurz und übersichtlich war. Wird der Programmcode länger, dann werden mehrere oder viele Ausdrücke eingesetzt und die Anzahl der Argumente für (defun) steigt.

Aufrufe von (defun) mit weniger als drei Argumenten erzeugen einen Fehler. Das ist logisch, da eine neu definierte Funktion sowohl einen Namen, eine Argumentenliste als auch mindestens eine Code-Anweisung haben muss. Eine Funktion ohne Namen wäre nicht aufzurufen, und eine Funktion ohne Code würde niemals etwas bewirken. Die Argumentenliste ist - wie bereits gesagt - einfach technisch unabdingbar.

Bis einschliesslich zur AutoCAD-Version 14 ist eine Funktion in AutoLISP eine Liste wie jede andere auch. Wir können also aus AutoCAD heraus unsere neue Funktion inspizieren, und das Ergebnis sollte uns nicht weiter überraschen:
!sqr  =>  ((zahl) (* zahl zahl))
                  
Ab AutoCAD 2000 sieht die Sache etwas anders aus. Wie wir ja bereits wissen, wird der Funktionscode nicht mehr wie in den älteren Versionen als lesbare Liste abgelegt, sondern er verschwindet hinter einer Kennzeichnung:
!sqr  =>  #<SUBR @01f112f8 SQR>
                  
Was passiert nun (in allen AutoCAD-Versionen), wenn wir die Funktion aufrufen? Das ist einfach erklärt: Wenn wir (sqr 5) eingeben, wird der Wert 5 vor Beginn der Evaluation an das Symbol zahl gebunden und der an das Symbol sqr gebundene Programmcode evaluiert.

Vielleicht ist Ihnen aufgefallen, dass wir gar nicht definiert haben, was die Rückgabe unserer Funktion sein soll. Das brauchen wir auch gar nicht. Rückgabe einer Funktion ist immer der Haupteffekt des letzten in der Funktion evaluierten Ausdrucks.

Wir könnten nun auf die Idee kommen, das hier gesagte dadurch zu überprüfen, dass wir !zahl auf der Kommandozeile eingeben. Die Rückgabe ist aber nil, und nicht etwa, wie wir erwarten könnten, 5. Woran liegt das? zahl ist ein Symbol, das nur innerhalb des Funktionsablaufes von (sqr) eine Wertbindung hat. zahl ist eine lokale Variable innerhalb von (sqr) und kann von ausserhalb weder manipuliert noch abgefragt werden. Sie werden sich mit zwei weiteren Begriffen anfreunden müssen: Sichtbarkeit und Lebensdauer von Variablen.

Die Sichtbarkeit von Zahl ist auf die Funktion (sqr) beschränkt. Ihre Lebensdauer ist identisch mit dem Zeitablauf der Funktion (sqr). Wir machen ein kleines Experiment und geben die folgenden Ausdrücke ein:
(setq zahl 12)    =>  12
(sqr 5)           =>  25
!zahl             =>  12
                  
Die Antworten auf unsere Eingaben lassen nur einen Schluss zu: Die Variable zahl, der wir hier den Wert 12 zugeordnet haben, kann nur eine ganz andere Variable sein als zahl in unserer Funktion (sqr). Die neue Variable zahl (mit dem Wert 12) nennt man eine globale Variable, ihre Lebensdauer endet erst dann, wenn wir sie auf nil setzen oder eine andere Zeichnung laden.

Wie verhält es sich aber mit ihrer Sichtbarkeit? Sie kann doch wohl innerhalb von (sqr) nicht sichtbar sein, denn dann gäbe es dort zwei Variablen mit dem gleichen Namen. Das kann aber niemals sein, denn der Zugriff auf solche Variablen wäre dann kaum oder gar nicht regelbar.

Die Argumente einer Funktion sind also lokal zu ihr, d.h. sie sind nur innerhalb dieser Funktion sichtbar. Wir können aber auch andere Symbole lokal machen. Dazu muss man nur folgendes wissen: Nach den Argumenten setzt man das Symbol / in die Formale-Argumente-Liste und kann dann nach dem Schrägstrich weitere Symbole angeben, die lokal sein sollen. Das kann z.B. so aussehen:
(defun neue-funktion(arg1 arg2 / lvar1 lvar2)  ... )
                  
Alle vier Symbole werden dadurch lokal. (neue-funktion) hat also zwei Argumente und zwei weitere lokale Variablen, die z.B. benutzt werden können, um Werte zwischenzuspeichern usw.

Es ist eine Eigentümlichkeit von AutoLISP, dass die Argumentenliste durch den Schrägstrich geteilt wird. Immerhin ist der Schrägstrich ja das Symbol, an das der Funktionscode der Division gebunden ist. Es wäre wahrscheinlich manches etwas einfacher bzw. verständlicher, wenn man die beiden Listen einfach geteilt hätte und die Definition des letzten Beispiels so aussehen würde:
(defun neue-funktion(arg1 arg2)(lvar1 lvar2)  ... )
                  
Es ist aber nun mal nicht so gemacht worden, und damit müssen wir leben. Ein häufig autretender Anfängerfehler ist, dass vergessen wird, rechts oder links des Schrägstriches Leerstellen zu lassen. Bei Klammern z.B. muss man keine Leerstellen lassen, da Klammern Operatoren sind. Der Schrägstrich jedoch ist ein Symbol wie jedes andere auch, und daher muss er mit Leerstellen von anderen Symbolen abgegrenzt werden. Lassen Sie uns die folgende falsche Eingabe untersuchen:
(defun neue-funktion(arg1 arg2 /lvar1 lvar2)  ... )
                  
Hier wird eine Funktion definiert, die 4 Argumente hat, jedoch keine weiteren lokalen Symbole. Das kommt daher, dass /lvar1 ein genauso gültiger Name für ein Symbol ist wie arg1 oder lvar2. Es hindert sie auch niemand daran, ein Symbol /// oder pi/2 zu nennen. Nicht gültig sind, wie bereits in einem der vorigen Kapitel erwähnt, lediglich die Zeichen, die für die Operatoren reserviert sind: ()"'.; und die Leerstelle.

Wenn Sie nach dieser Definition (neue-funktion) mit zwei Argumenten aufrufen, werden Sie jedenfalls die Fehlermeldung 'Falsche Anzahl Argumente' erhalten.


Übungsaufgaben

  1. Welche Argumente von (defun) werden automatisch quotiert?

  2. Welche der folgenden Aussagen sind richtig?
    • Funktionen werden definiert, wenn abzusehen ist, dass der selbe Vorgang mehrmals in einem Programm ablaufen soll

    • Funktionsdefinitionen sparen Schreibarbeit und Speicherplatz

    • Selbstdefinierte Funktionen waren bis AutoCAD 14 ganz normale Listen, sind es aber seit AutoCAD 2000 nicht mehr

    • Die Rückgabe einer Funktion ist immer der Nebeneffekt des letzten evaluierten Ausdrucks

    • Wenn man eine Funktion ohne Argumente definiert, kann die Formale-Argumenten-Liste weggelassen werden

  3. Definieren Sie folgende Funktionen:
    • Eine Funktion, die ein Argument erhält und das Argument immer unverändert zurückgibt

    • Eine Funktion ohne Argumente, die immer nil zurückgibt

    • Eine Funktion, die nur den Nachkomma-Anteil einer Realzahl zurückgibt

    • Eine Funktion, die zwei Listen als Argumente erhält und eine Liste aus den beiden jeweils ersten Elementen zurückgibt

    • Eine Funktion, die eine Liste ohne das letzte Element zurückgibt

    • Eine Funktion, die das vorletzte Element einer Liste zurückgibt