Im allgemeinen bezeichnet man die Rückgabe einer Funktion
als den Effekt bzw. Haupteffekt. Wenn man also
(+ 3 4)
eingibt, ist das Ergebnis 7 der Effekt der Funktion. Den
Effekt einer Funktion kann man direkt als Argument für einen
anderen Funktionsaufruf benutzen:
(* 6(+ 3 4)) => 42
Der Effekt von
(+ 3 4) wird hier als zweites Argument für die
Funktion
(*) verwendet. Wenn nun aber eine Funktion irgendetwas
bewirkt, das keinen Niederschlag in der Rückgabe findet, so
bezeichnet man das, was die Funktion bewirkt, als den Nebeneffekt
der Funktion. Ein Beispiel für ausgeprägt Nebeneffekte haben die
beiden Funktionen
(textscr) und
(graphscr). Man kann
mit ihnen auf den Text- bzw. Grafikbildschirm (oder das entspr.
Fenster) umschalten. Der Effekt (die Rückgabe) dieser beiden
Funktionen ist immer
nil.
Auch wenn die Bezeichnungen dies vielleicht suggerieren, es ist
nicht so, daß der Effekt immer wichtig und der Nebeneffekt immer
unwichtig ist. Auch das Gegenteil kann der Fall sein, wie bei
den beiden letztgenannten Funktionen deutlich wird!
Es gibt in AutoLISP keine Funktion, die gar keinen Haupteffekt hat
und nur Nebeneffekte erzeugt. Bei den Funktionen, die ausschließlich
ihrer Nebeneffekte wegen aufgerufen werden, wird immer nil zurückgegeben
(z.B. bei
(textscr) und
(graphscr)). Es gibt allerdings
auch Funktionen mit ausgeprägtem Nebeneffekt, die trotzdem eine
wichtige Rückgabe erzeugen. Nehmen wir als Beispiel die Funktion
(open), mit der man eine Datei zum Lesen oder schreiben öffnen
kann. Der Zweck der Funktion ist das Öffnen der Datei, in diesem
Falle wird die Datei also wegen ihres Nebeneffekts aufgerufen.
Der Haupteffekt ist aber die Rückgabe des Datei-handles der geöffneten
Datei. Ohne diesen kann man weder aus der Datei lesen noch etwas
hineinschreiben. Gibt die Funktion
(open) nil zurück, dann konnte
der Nebeneffekt (das Öffnen) nicht ausgeführt werden, z.B. weil der
Dateiname ungültig war, der Pfad nicht stimmte usw. Bei
(textscr)
und
(graphscr) wird auf eine solche interpretierbare Rückgabe
verzichtet, da es nicht vorkommen kann, dass das Umschalten
zwischen den Fenstern nicht funktioniert.
Welche der Funktionen, die wir bisher kennengelernt haben, führen
denn Nebeneffekte aus? Wenn wir die Beispiele der letzten Absätze,
(textscr),
(graphscr) und
(open), einmal außer
acht lassen, dann bleiben nur zwei Funktionen übrig: Es handelt
sich um
(set) und
(setq).
Nur diese beiden Funktionen ändern die Daten im Speicher tatsächlich,
alle anderen (sämtliche behandelten Funktionen zur Listenbearbeitung
z.B.) werden nur des Haupteffekts wegen aufgerufen.
(setq)
wird fast immer seiner Nebeneffekte wegen aufgerufen, den Haupteffekt
kann man benutzen, um ein wenig Schreibarbeit zu sparen. Dazu ein
Beispiel:
;Wir binden drei Werte an drei Symbole
(setq a 7) => 7
(setq b 8) => 8
(setq c 9) => 9
(setq d(+ a b c)) => 24
Das hätten wir auch so formulieren können:
(setq a 7 b 8 c 9) => 9
(setq d(+ a b c)) => 24
Der Aufruf von
(setq) hier zeigt schon, daß in diesem Fall
(mehrfache Zuweisungen mit einem einzigen Aufruf) das Interesse
am Haupteffekt gering ist. Es wird schließlich nur der Wert der
dritten Zuweisung zurückgegeben. Für die ersten beiden Zuweisungen
gibt es keinen Effekt. Wir können jetzt aber noch einen Schritt
weitergehen:
(setq d(+(setq a 7)(setq b 8)(setq c 9)))
In dieser Variante benutzen wir konsequent sowohl die Effekte als
auch die Nebeneffekte. Effekt ist, daß d die Summe von a,b und c
enthält; Nebeneffekt ist, daß alle vier Variablen anschließend
im Speicher stehen und weiterhin benutzt werden können. Um es
noch einmal zu betonen - in diesem Beispiel ist (soweit man
solche Programmfragmente überhaupt beurteilen kann) der Nebeneffekt
sicherlich wichtiger als der Haupteffekt.
Was hier ganz zum Schluß auch noch klar werden sollte, ist Folgendes:
Wenn man eine Funktion aufruft, ohne daß ihr Effekt (ihre Rückgabe)
als Argument an eine andere Funktion weitergegeben wird, dann wurde
diese Funktion nur um ihrer Nebeneffekte willen aufgerufen. Jede
Rückgabe, die nicht als Argument verwendet wird, verpufft. Natürlich
wenden wir gerade die Technik der verpufften Rückgabe ständig in
unseren Beispielen an.
Wenn wir aus AutoCAD heraus einen Ausdruck an LISP übergeben, wird
die Rückgabe an die AutoCAD-Kommandozeile übergeben und dort
ausgedruckt. Wir können Sie zwar lesen, aber nicht wieder verwenden
- sie ist am Bilschirm verpufft. Verpuffung von Effekten läßt sich
also nur durch Verschachtelung (Weitergabe von Haupteffekten als
Argumente an andere Funktionen) oder durch Anwendung von Nebeneffekten
(Zuweisen der Rückgabe mittels
(set) bzw.
(setq) an
Variablen) verhindern.
All dies klingt - so theoretisch abgehandelt - wesentlich
komplizierter als es wirklich ist. Machen wir uns die Dinge noch
einmal an einem Beispiel klar:
(setq farben(list "rot" "grün" "blau"))
=> ("rot" "grün" "blau")
Den Effekt lassen wir am Bildschirm verpuffen, Nebeneffekt ist, daß
wir ab jetzt auf die Variable farben zurückgreifen können.
(append farben '("gelb"))
=> ("rot" "grün" "blau" "gelb")
Die Rückgabe verpufft am Bildschirm, denn wenn wir uns unsere Liste
anschließend ansehen, hat sie noch immer nur drei Elemente.
(setq farben(append farben '("gelb")))
=> ("rot" "grün" "blau" "gelb")
Jetzt erscheint am Bildschirm dieselbe Ausgabe, trotzdem ist der
Sachverhalt ganz anders: Die Rückgabe von
(append) verpufft
nicht mehr, sondern wird an
(setq) als Argument weitergeleitet.
Durch den Nebeneffekt von
(setq) werden die Daten tatsächlich
geändert. Wenn wir ab jetzt auf die Liste
farben zugreifen,
hat sie tatsächlich vier Elemente. Lediglich der Effekt von
(setq) verpufft jetzt am Bildschirm. Das macht aber nichts,
da wir ja
(setq) des Nebeneffekts wegen aufgerufen haben.
Übungsaufgaben
-
-