In der Programmierung bezeichnet Wirkung[1] (engl. effect) die Veränderung des Zustands, in dem sich ein Computersystem befindet. Beispiele sind das Verändern von Inhalten des Speichers oder die Ausgabe eines Textes auf Bildschirm oder Drucker.

Da solche Wirkungen in den meisten Programmiersprachen etwas ganz Gewöhnliches darstellen, wird ihr Vorhandensein außerhalb der theoretischen Informatik meist nicht weiter thematisiert. Der Begriff wird vor allem dort gebraucht, wo Wirkungen entweder ganz fehlen oder wo die Abgrenzung verschiedenartiger Wirkungen voneinander betont werden soll. Letzteres wird „Nebenwirkung“, häufig auch „Nebeneffekt“ genannt. Auch die Bezeichnung „Seiteneffekt“, eine falsche Rückübersetzung des englischen side effect, ist weit verbreitet.

Da der Computer als streng deterministische Maschine immer nur genau das tun kann, wofür er programmiert wurde, wäre eine Unterscheidung zwischen Haupt- und Nebenwirkung eigentlich nicht zulässig. Die konkrete Definition ist daher vom Kontext abhängig. Zum Teil wird auf eine Unterscheidung bewusst verzichtet und die Begriffe synonym verwendet.[1]

Wirkung als Zustandsänderung

Bearbeiten

Hauptartikel: Operationale Semantik

Die gängigen imperativen Programmiersprachen wie zum Beispiel C++ oder Java verwenden Variablen als wichtiges Ausdrucksmittel der Sprache. Eine Variable repräsentiert zu jedem Zeitpunkt des Programmablaufes einen ganz bestimmten Wert. Die Gesamtheit aller Variablen und ihrer Werte definiert den Programmzustand. Operationen werden immer auf einem solchen Zustand ausgeführt und verändern ihn. Eine solche Zustandsänderung wird Nebenwirkung[2][3] genannt (engl. side effect).

Eine strenge Unterscheidung zwischen Nebenwirkung und Wirkung findet im Rahmen dieser Definition nicht statt – die Begriffe werden häufig sogar synonym verwendet. Die Bezeichnung als Nebenwirkung ist hier so zu verstehen, dass die „hauptsächliche“ Wirkung einer Operation beispielsweise in der Errechnung der Summe zweier Zahlen besteht. Die „nebensächliche“ Wirkung besteht darin, das Ergebnis dieser Berechnung in einer Variable abzulegen.

Wirkungsfreiheit in der rein funktionalen Programmierung

Bearbeiten

In der rein funktionalen Programmierung wird – anders als in den imperativen Sprachen wie C++ oder Java – das Ergebnis eines Algorithmus allein mit Ausdrücken und Funktionen beschrieben. Es werden keine Variablen und keine Wertezuweisungen verwendet. In der rein funktionalen Programmierung treten deshalb keine Zustandsänderungen im Sinne der obigen Definition und somit auch keine Nebenwirkungen (side effects) auf.[2] Die Programmiersprache ist zustandslos und seiteneffektfrei.[3]

Diese Eigenschaft einer Programmiersprache wird als referenzielle Transparenz bezeichnet. Sie besagt, dass der Wert eines Ausdrucks nur von seiner Umgebung abhängt und nicht vom Zeitpunkt oder einer bestimmten Reihenfolge der Auswertung.[4] Das Fehlen von Nebenwirkungen dieser Art wird entsprechend „Seiteneffektfreiheit“[3], gelegentlich auch „Wirkungsfreiheit“ genannt. Beispiele für gänzlich wirkungsfreie Sprachen sind die rein funktionale Programmiersprache Haskell oder reines (pure) Lisp.

In anderen funktionalen Programmiersprachen wie etwa Scheme können Prozeduraufrufe die Werte von Variablen verändern oder Bildschirmausgaben auslösen. Diese Seiteneffekte sind ein wichtiges Ausdrucksmittel der Sprache, die referenzielle Transparenz geht jedoch verloren und Scheme ist damit keine rein funktionale Sprache mehr.[4] Um diese Eigenschaft in der für Lehrzwecke eingesetzten Sprache Scheme hervorzuheben, werden seiteneffektbehaftete Prozeduren mit einem Ausrufezeichen gekennzeichnet, zum Beispiel in der Variablenzuweisung (set! a 2).

Beispiel

Bearbeiten

Das folgende, mit seinen Klammern und der Präfixnotation für eine Sprache wie Lisp oder Scheme typische Beispielprogramm liefert abhängig von einer Bedingung eines von zwei möglichen Berechnungsergebnissen zurück.

(if (= a 0)
  (+ a 1)
  (* a 2))

Die Zuweisung des Ergebnisses zu einer Variable findet nicht statt. Insbesondere aber hat die Reihenfolge der Auswertung der einzelnen Funktionen (if, =, + und *) keinerlei Einfluss auf das Ergebnis. Jeder Ausdruck kann an jeder Stelle durch seinen Wert ersetzt werden. Das ist die referenzielle Transparenz.

Nebenwirkung in der prozedurorientierten Programmierung

Bearbeiten

In der prozedurorientierten Programmierung wird ein Algorithmus in Module, sogenannte Prozeduren zerlegt. Diese werden als „schwarze Kästen“ Black Box) betrachtet, von denen nach Außen hin lediglich ihre Schnittstelle, das heißt ihr Name und ihre zulässigen Eingabe- (auch Argumente genannt) und Resultatobjekte bekannt sind.

Eine Nebenwirkung wird in diesem Zusammenhang als Wirkung definiert, die nicht in der Schnittstellenbeschreibung der Prozedur spezifiziert ist.[2] Typischerweise ist das der Fall, wenn eine Prozedur auf globale Variablen oder andere Speicherbereiche außerhalb des Schnittstelle entweder zugreift oder diese sogar verändert.

Prozeduren, die über eine „saubere“ Schnittstelle in diesem Sinne verfügen und ihre Umgebung unangetastet lassen, werden dementsprechend seiten- oder nebeneffektfrei genannt.

Beispiel

Bearbeiten

Das folgende, vereinfacht dargestellte C#-Beispielprogramm enthält eine Prozedur, deren Schnittstelle mit dem Namen „berechnen“ sowie einem ganzzahligen (Integer) Eingabe- und einem ebenfalls ganzzahligen Ausgabeobjekt vollständig beschrieben ist.

int globale_variable = 2;
int berechnen(int argument) //Schnittstelle der Prozedur
{
    globale_variable = globale_variable + argument;
    return globale_variable; //Zugriff auf Variable außerhalb der Schnittstelle
}
Console.WriteLine(berechnen(4)); //Erster Aufruf der Prozedur
Console.WriteLine(berechnen(4)); //Zweiter Aufruf der Prozedur

Die Prozedur berechnet beim ersten Aufruf den erwarteten Wert 6 und liefert ihn als Ergebnis zurück. Gleichzeitig wird durch einen (im gezeigten Beispiel ungewollten) Seiteneffekt der Wert der globalen Variablen verändert, die nicht Teil der Schnittstellenbeschreibung ist. Der zweite, eigentlich identische Aufruf liefert einen anderen Wert zurück, in diesem Fall 10. Die Prozedur ist „seiteneffektbehaftet“.

Nebenwirkung im weiteren Sinne

Bearbeiten

Im weiteren Sinne bezeichnet Nebenwirkung, häufig auch Nebeneffekt oder Seiteneffekt[5] (von engl. side effect) genannt, allgemein eine implizierte Nebenwirkung eines Hard- oder Softwaresystems. Nebeneffekte sind häufig nur durch genaue Kenntnis und Analyse der Programmiersprache und des verwendeten Gesamtsystems nachvollziehbar und stellen daher mögliche, besonders schwer auffindbare Fehlerquellen dar. Sie können jedoch auch gezielt als Ausdrucksmittel einer Programmiersprache eingesetzt werden.

Seiteneffektbehaftete (und damit oftmals fehlerhafte) Softwareprogramme sind von Eigenschaften der Umgebung abhängig, die sich der Kontrolle des Benutzers entziehen. Das können beispielsweise bestimmte Zustände von Speicherzellen im Arbeitsspeicher sein, die vom Programm aufgrund einer fehlenden oder unvollständigen Initialisierung nicht mit den erwarteten Ausgangswerten vorbelegt wurden. Abhängig vom Zustand der Umgebung – etwa wann das System zuletzt neu gestartet wurde, welche anderen Programme bereits geladen wurden etc. – kann von zwei identischen Durchläufen eines seiteneffektbehafteten Programms einer erfolgreich sein und einer aus nicht nachvollziehbaren Gründen zum Absturz führen. Häufig erweckt dies den Eindruck, das Funktionieren des Programms sei von der Zeit abhängig.

Beispiel

Bearbeiten

Der in einer Programmiersprache wie C++ oder Java lauffähige Ausdruck b = 1 + a; weist der Variablen b den um Eins erhöhten Wert der Variablen a zu. Die (gewollte und offensichtliche) Wirkung dieses Ausdrucks besteht darin, dass die Variable b und damit die Speicherzelle, in der ihr ursprünglicher Wert abgelegt war, ihren Zustand verändert hat. Sie enthält jetzt das Ergebnis der auf der rechten Seite des Ausdrucks durchgeführten Berechnung.

Im Gegensatz dazu weist der Ausdruck b = ++a; einen Nebeneffekt auf. Wie im vorigen Beispiel erhält die Variable b den um Eins erhöhten Wert der Variable a. Zusätzlich wurde der Wert der Variable a durch den Präfixoperator ++ ebenfalls um Eins erhöht.

Diese Nebeneffekte sind möglicherweise gewollt, aber weniger offensichtlich und vor allem deshalb fehleranfällig, weil die Wertigkeiten des Zuweisungs- und des Inkrementoperators je nach Programmiersprache und Compiler verschieden oder sogar undefiniert sein können.

Einzelnachweise

Bearbeiten
  1. a b Jörg Demmer: Prozeduren, Funktionen, Methoden. Johann Wolfgang Goethe-Universität, Frankfurt am Main 2006.
  2. a b c P. Rechenberg, G. Pomberger: Informatik-Handbuch. Carl Hanser Verlag, München/Wien 2006, ISBN 978-3-446-40185-3.
  3. a b c C. Wagenknecht: Programmierparadigmen. Teubner, Wiesbaden 2004, ISBN 978-3-519-00512-4.
  4. a b C. Schiedermeier: Funktionales Programmieren. Nürnberg 2002.
  5. I. O. Kerner: Informatik. Deutscher Verlag der Wissenschaften, Berlin 1990, ISBN 3-326-00189-4.

Kategorie:Programmierung