it-swarm.com.de

Was ist eine "Nebenwirkung"?

Ich habe das Konzept der Nebenwirkung nicht klar verstanden.

  • Was ist ein Nebeneffekt bei der Programmierung?
  • Ist die Programmiersprache abhängig?
  • Gibt es externe und interne Nebenwirkungen?

Bitte geben Sie ein Beispiel für Ursachen, die Nebenwirkungen verursachen.

101
Amir Rezaei

Ein Nebeneffekt bezieht sich einfach auf die Änderung eines Zustands - zum Beispiel:

  • Ändern des Werts einer Variablen;
  • Schreiben einiger Daten auf die Festplatte;
  • Aktivieren oder Deaktivieren einer Schaltfläche in der Benutzeroberfläche.

Im Gegensatz zu zu dem, was manche Leute zu sagen scheinen:

  • Ein Nebeneffekt muss nicht versteckt oder unerwartet sein (es kann sein, aber das hat nichts mit der Definition zu tun, wie sie für die Informatik gilt) ;;

  • Ein Nebeneffekt hat nichts mit Idempotenz zu tun. Eine idempotente Funktion kann Nebenwirkungen haben, und eine nicht idempotente Funktion kann keine Nebenwirkungen haben (z. B. das Abrufen des aktuellen Systemdatums und der aktuellen Systemzeit).

Es ist wirklich sehr einfach. Nebeneffekt = irgendwo etwas ändern.

P.S. Wie der Kommentator Benjamin hervorhebt, können mehrere Personen die Definition eines Nebeneffekts mit der Definition von reine Funktion in Verbindung bringen. Dies ist eine Funktion, die (a) idempotent ist und (b) keine Nebeneffekte hat. Auswirkungen. Das eine impliziert nicht das andere in der allgemeinen Informatik, aber funktionale Programmiersprachen werden typischerweise dazu neigen, beide Einschränkungen durchzusetzen.

114
Aaronaught

Jede Operation, die den Zustand des Computers verändert oder mit der Außenwelt interagiert, soll eine Nebenwirkung haben. Siehe Wikipedia zu Nebeneffekt .

Zum Beispiel hat diese Funktion keine Nebenwirkungen. Das Ergebnis hängt nur von den Eingabeargumenten ab, und beim Aufruf ändert sich nichts über den Status des Programms oder seiner Umgebung:

int square(int x) { return x * x; }

Im Gegensatz dazu erhalten Sie beim Aufrufen dieser Funktionen unterschiedliche Ergebnisse, abhängig von der Reihenfolge, in der Sie sie aufrufen, da sie etwas am Status des Computers ändern:

int n = 0;
int next_n() { return n++; }
void set_n(int newN) { n = newN; }      

Diese Funktion hat den Nebeneffekt, dass Daten in die Ausgabe geschrieben werden. Sie rufen die Funktion nicht auf, weil Sie ihren Rückgabewert möchten. Sie nennen es, weil Sie die Wirkung wollen, die es auf die "Außenwelt" hat:

int Write(const char* s) { return printf("Output: %s\n", s); }
38

Ich denke, dass die vorhandenen Antworten ziemlich gut sind. Ich möchte auf einige Aspekte eingehen, die IMO nicht genug betont hat.

In der Mathematik ist eine Funktion nur eine Abbildung von einem Tupel von Werten auf einen Wert. Wenn also eine Funktion f und ein Wert x gegeben sind, ist f(x) immer das gleiche Ergebnis y. Sie können f(x) überall in einem Ausdruck durch y ersetzen, und nichts wird sich ändern.

Was in vielen Programmiersprachen als Funktion (oder Prozedur) bezeichnet wird, ist ein Konstrukt (Code), das ausgeführt werden kann, weil:

  1. Es berechnet eine Funktion im mathematischen Sinne, d. H. Bei gegebenen Eingabewerten gibt es ein Ergebnis zurück, oder
  2. Es erzeugt einen gewissen Effekt, z. druckt etwas auf den Bildschirm, ändert einen Wert in einer Datenbank, startet Raketen, schläft 10 Sekunden lang und sendet eine SMS.

So können Effekte mit dem Zustand, aber auch mit anderen Aspekten wie dem Abfeuern einer Rakete oder dem Anhalten der Ausführung für einige Sekunden in Verbindung gebracht werden.

Der Begriff Nebenwirkung mag negativ klingen, aber normalerweise ist der Effekt des Aufrufs einer Funktion der eigentliche Zweck der Funktion. Ich nehme an, da der Begriff Funktion ursprünglich in der Mathematik verwendet wurde, wird die Berechnung eines Wertes als Primäreffekt einer Funktion betrachtet, während alle anderen Effekte als Nebenwirkungen betrachtet werden . Einige Programmiersprachen verwenden den Begriff Prozedur, um Verwechslungen mit Funktionen im mathematischen Sinne zu vermeiden.

Beachten Sie, dass

  1. Einige Verfahren sind sowohl für ihren Rückgabewert als auch für ihre Nebenwirkung nützlich.
  2. Einige Prozeduren berechnen nur einen Ergebniswert und haben keine anderen Auswirkungen. Sie werden oft als reine Funktionen bezeichnet, weil sie lediglich eine Funktion im mathematischen Sinne berechnen.
  3. Einige Verfahren, z. sleep() in Python sind nur wegen ihrer (Nebenwirkungen) nützlich. Diese werden häufig als Funktionen modelliert, die einen speziellen Wert None oder unit oder () Oder ... zurückgeben, was lediglich anzeigt, dass die Berechnung korrekt beendet wurde.
24
Giorgio

Ein Nebeneffekt liegt vor, wenn eine Operation Auswirkungen auf eine Variable/ein Objekt hat, die bzw. das außerhalb der beabsichtigten Verwendung liegt.

Dies kann passieren, wenn Sie eine komplexe Funktion aufrufen, die den Nebeneffekt hat, eine globale Variable zu ändern, obwohl dies nicht der Grund war, warum Sie sie aufgerufen haben (vielleicht haben Sie sie aufgerufen, um etwas aus einer Datenbank zu extrahieren).

Ich gebe zu, ich habe Probleme, ein einfaches Beispiel zu finden, das nicht völlig erfunden aussieht, und Beispiele aus Sachen, an denen ich gearbeitet habe, sind viel zu lang, um sie hier zu posten (und da es arbeitsbezogen ist, sollte ich es wahrscheinlich sowieso nicht tun ).

Ein Beispiel, das ich (vor einiger Zeit) gesehen habe, war eine Funktion, die eine Datenbankverbindung öffnete, wenn die Verbindung geschlossen war. Das Problem war, dass die Verbindung am Ende der Funktion geschlossen werden sollte, der Entwickler jedoch vergaß, diesen Code hinzuzufügen. Hier gab es also einen unbeabsichtigten Nebeneffekt: Das Aufrufen einer Prozedur sollte nur eine Abfrage durchführen, und der Nebeneffekt war, dass die Verbindung offen blieb und wenn Die Funktion wurde zweimal hintereinander aufgerufen. Es wurde ein Fehler ausgegeben, der besagte, dass die Verbindung bereits geöffnet war.


Ok, da jetzt alle Beispiele geben, denke ich, dass ich es auch tun werde;)

/*code is PL/SQL-styled pseudo-code because that's what's on my mind right now*/

g_some_global int := 0; --define a globally accessible variable somewhere.

function do_task_x(in_a in number) is
begin
    b := calculate_magic(in_a);
    if b mod 2 == 0 then
        g_some_global := g_some_global + b;
    end if;
    return (b * 2.3);
end;

Die Funktion do_task_x hat einen primären Effekt, der das Ergebnis einiger Berechnungen zurückgibt, und einen seitlichen Effekt, möglicherweise eine globale Variable zu ändern.

Natürlich kann , welches das primäre und welches der Nebeneffekt ist, interpretiert werden und von der tatsächlichen Verwendung abhängen. Wenn ich diese Funktion aufrufe, um den globalen Wert zu ändern, und den zurückgegebenen Wert verwerfe, würde ich sagen, dass das Ändern des globalen Werts der primäre Effekt ist.

In der Informatik soll eine Funktion oder ein Ausdruck eine Nebenwirkung haben, wenn sie einen Zustand verändert oder eine beobachtbare Wechselwirkung mit aufrufenden Funktionen oder der Außenwelt aufweist.

Von Wikipedia - Nebeneffekt

Eine Funktion im mathematischen Sinne ist eine Abbildung von Eingabe zu Ausgabe. Der beabsichtigte Effekt des Aufrufs einer Funktion besteht darin, dass die Eingabe der zurückgegebenen Ausgabe zugeordnet wird. Wenn die Funktion etwas anderes tut, spielt es keine Rolle, was passiert, aber wenn sie ein Verhalten aufweist, das die Eingabe nicht der Ausgabe zuordnet, ist dieses Verhalten als Nebeneffekt bekannt.

Allgemeiner ausgedrückt ist ein Nebeneffekt ein Effekt, der nicht der beabsichtigte Effekt des Konstrukteurs des Konstrukts ist.

Ein Effekt ist alles, was einen Schauspieler betrifft. Wenn ich eine Funktion aufrufe, die meiner Freundin eine Trennungs-Textnachricht sendet, die eine Reihe von Schauspielern betrifft, mich, sie, das Netzwerk der Mobilfunkgesellschaft usw. Der einzige beabsichtigte Effekt des Aufrufs einer nebenwirkungsfreien Funktion betrifft die Funktion um mir ein Mapping von meiner Eingabe zurückzugeben. So für:

   public void SendBreakupTextMessage() {
        Messaging.send("I'm breaking up with you!")
   }

Wenn dies eine Funktion sein soll, sollte es nur void zurückgeben. Wenn es nebenwirkungsfrei war, sollte es die Textnachricht nicht senden.

In den meisten Programmiersprachen gibt es kein Konstrukt für eine mathematische Funktion. Kein Konstrukt soll als solches verwendet werden. Deshalb sagen die meisten Sprachen, dass Sie Methoden oder Verfahren haben. Diese sollen von Natur aus viel mehr Effekte erzielen können. In der allgemeinen Programmiersprache kümmert sich niemand wirklich um die Absicht einer Methode oder Prozedur . Wenn also jemand sagt, dass diese Funktion Nebenwirkungen hat, bedeutet dies effektiv, dass sich dieses Konstrukt nicht verhält wie eine mathematische Funktion. Und wenn jemand sagt, diese Funktion sei nebenwirkungsfrei, verhält sich dieses Konstrukt effektiv wie eine mathematische Funktion.

Eine reine Funktion ist per Definition immer nebenwirkungsfrei. Eine reine Funktion ist eine Möglichkeit zu sagen, dass diese Funktion, obwohl sie ein Konstrukt verwendet, das mehr Effekte zulässt, nur einen Effekt hat, der dem einer mathematischen Funktion entspricht.

Ich fordere jeden auf, mir zu sagen, wann eine nebenwirkungsfreie Funktion nicht rein wäre. Sofern die primäre beabsichtigte Wirkung des Satzkontexts unter Verwendung des Begriffs rein und nebenwirkungsfrei nicht die der mathematisch beabsichtigten Wirkung einer Funktion ist, sind diese immer gleich.

Als solches manchmal, wenn auch seltener, und ich glaube, dies ist die Unterscheidung, die in der akzeptierten Antwort fehlt und auch Menschen irreführt (da dies nicht die häufigste Annahme ist), aber manchmal wird angenommen, dass die beabsichtigte Wirkung einer Programmierfunktion ist Eingabe auf Ausgabe abbilden, wobei die Eingabe nicht auf die expliziten Parameter der Funktion beschränkt ist, die Ausgabe jedoch auf den expliziten Rückgabewert beschränkt ist. Wenn Sie davon ausgehen, dass dies der beabsichtigte Effekt ist, ist eine Funktion, die eine Datei liest und basierend auf dem Inhalt der Datei ein anderes Ergebnis zurückgibt, immer noch nebenwirkungsfrei, da Sie Eingaben von anderen Stellen in Ihrem beabsichtigten Effekt zugelassen haben.

Warum ist das alles wichtig?

Es geht darum, die Kontrolle zu behalten und zu behalten. Wenn Sie eine Funktion aufrufen und sie etwas anderes tut als einen Wert zurückzugeben, ist es schwierig, über ihr Verhalten nachzudenken. Sie müssen in der Funktion nach dem tatsächlichen Code suchen, um zu erraten, was er tut, und seine Richtigkeit bestätigen. Die ideale Situation ist, dass es sehr klar und einfach ist zu wissen, welche Eingabe die Funktion verwendet, und dass sie nichts anderes tut, als eine Ausgabe dafür zurückzugeben. Sie können dies ein wenig lockern und sagen, dass es nicht so hilfreich ist, genau zu wissen, welche Eingabe verwendet wird, als sicher zu sein, dass nichts anderes getan wird, von dem Sie möglicherweise nicht wissen, dass Sie einen Wert zurückgeben. Vielleicht sind Sie also damit zufrieden, nur die Durchsetzung durchzusetzen dass es nichts anderes tut, als Eingaben zuzuordnen, egal woher es kommt, um sie auszugeben.

In fast allen Fällen besteht der Sinn eines Programms darin, andere Effekte zu erzielen als die Zuordnung von Dingen zu Dingen, die herauskommen. Die Idee, den Nebeneffekt zu kontrollieren, besteht darin, dass Sie Code so organisieren können, dass er leichter zu verstehen und zu verstehen ist. Wenn Sie alle Nebenwirkungen an einem Ort zusammenfassen, der sehr explizit und zentral ist, ist es einfach zu wissen, wo Sie suchen müssen, und darauf zu vertrauen, dass dies alles ist, was passiert, nicht mehr. Wenn die Eingabe auch sehr explizit ist, hilft dies, das Verhalten für verschiedene Eingaben zu testen, und es ist einfacher zu verwenden, da Sie die Eingabe nicht an vielen verschiedenen Stellen ändern müssen, von denen einige möglicherweise nicht offensichtlich sind um zu bekommen was du willst.

Da es am hilfreichsten ist, das Verhalten eines Programms zu verstehen, zu begründen und zu steuern, ist es, alle Eingaben klar und explizit zu gruppieren und alle Nebenwirkungen zusammen und explizit zu gruppieren. Dies ist im Allgemeinen das, worüber die Leute sprechen, wenn sie sagen Nebenwirkung, rein usw.

Da die Gruppierung der Nebenwirkungen und ihre Aussagekraft am hilfreichsten ist, meinen die Menschen dies manchmal nur und unterscheiden sie, indem sie sagen, dass sie nicht rein, aber dennoch "nebenwirkungsfrei" sind. Die Nebenwirkung ist jedoch relativ zu der angenommenen "beabsichtigten primären Wirkung", daher handelt es sich um einen Kontextbegriff. Dies wird meiner Meinung nach seltener verwendet, obwohl überraschenderweise in diesem Thread viel darüber gesprochen wird.

Idempotent bedeutet schließlich, dass das mehrfache Aufrufen dieser Funktion mit denselben Eingaben (unabhängig davon, woher sie kommen) immer zu denselben Effekten führt (Nebeneffekt oder nicht).

3
Didier A.

Bei der Programmierung tritt ein Nebeneffekt auf, wenn eine Prozedur eine Variable von außerhalb ihres Gültigkeitsbereichs ändert. Nebenwirkungen sind nicht sprachabhängig. Es gibt einige Sprachklassen, die darauf abzielen, Nebenwirkungen zu beseitigen (reine funktionale Sprachen), aber ich bin mir nicht sicher, ob es Nebenwirkungen gibt, die Nebenwirkungen erfordern, aber ich könnte mich irren.

Soweit ich weiß, gibt es keine internen und externen Nebenwirkungen.

2
indyK1ng

Hier ist ein einfaches Beispiel:

int _totalWrites;
void Write(string message)
{
    // Invoking this function has the side effect of 
    // incrementing the value of _totalWrites.
    _totalWrites++;
    Debug.Write(message);
}

Die Definition der Nebenwirkung ist nicht programmierspezifisch. Stellen Sie sich also einfach die Nebenwirkungen Ihrer Medikamente vor oder essen Sie zu viel.

0
ChaosPandion