Che cos'è un "effetto collaterale?"


89

Non ho capito chiaramente il concetto di effetto collaterale.

  • Qual è l'effetto collaterale nella programmazione?
  • Dipende dal linguaggio di programmazione?
  • Esistono effetti collaterali esterni ed interni?

Fornisci alcuni esempi di cause che creano effetti collaterali.


7
Assomiglia molto ai compiti.
gnasher729,

3
@ gnasher729 a chi importa questo è TREMENDOUSLY utile :)
Charlie Parker

Risposte:


109

Un effetto collaterale si riferisce semplicemente alla modifica di un qualche tipo di stato - ad esempio:

  • Modifica del valore di una variabile;
  • Scrivere alcuni dati su disco;
  • Abilitazione o disabilitazione di un pulsante nell'interfaccia utente.

Contrariamente a ciò che alcune persone sembrano dire:

  • Un effetto collaterale non deve essere nascosto o inaspettato (può essere, ma ciò non ha nulla a che fare con la definizione come si applica all'informatica);

  • Un effetto collaterale non ha nulla a che fare con l'idempotenza. Una funzione idempotente può avere effetti collaterali e una funzione non idempotente potrebbe non avere effetti collaterali (come ottenere la data e l'ora correnti del sistema).

È davvero molto semplice. Effetto collaterale = cambiare qualcosa da qualche parte.

PS Come sottolinea Benjol, molte persone potrebbero confondere la definizione di effetto collaterale con la definizione di una funzione pura , che è una funzione che è (a) idempotente e (b) non ha effetti collaterali. Uno non implica l'altro nell'informatica generale, ma i linguaggi di programmazione funzionale in genere tenderanno a far rispettare entrambi i vincoli.


38
La frase "effetto collaterale" fa sembrare che qualcos'altro sia cambiato diversamente da quello che era previsto. In medicina, un farmaco avrà un effetto principale nella riduzione del dolore, e talvolta un effetto collaterale di causare emorragie al naso, vertigini, ecc ... lo scopo del farmaco non è quello di causare emorragie al naso, ma a volte ciò accade come risultato extra non intenzionale .
FrustratedWithFormsDesigner,

15
@Frustrato: +1. Ogni volta che vedo quel termine non posso fare a meno di chiedermi se non è stato scelto dai sostenitori di FP per creare precisamente quella connotazione sottilmente sinistra.
Mason Wheeler,

6
@Mason Wheeler. Esisteva molto prima di FP. E non è una connotazione sottilmente sinistra. È un male assoluto e lo è sempre stato. Per i 3 decenni in cui ho programmato, la dichiarazione "cripto-assegnazione" - l'effetto collaterale - ha turbato le persone. Una semplice vecchia istruzione di assegnazione è molto più semplice da gestire.
S. Lott,

7
@Mason Wheeler: in C ++a.. Non sembra un compito. b = ++a;ha due effetti collaterali. Quello ovvio e la cripto-assegnazione di a. Questo è il tipo di cosa che è un effetto collaterale che (per alcuni) è desiderabile. Ma è stato chiamato un effetto collaterale per tutta la mia carriera per renderlo non sottile.
S. Lott,

5
@Zachary, per favore vedi l'ultimo punto nella mia risposta. Ciò a cui ti riferisci è un comportamento idempotente (o la sua mancanza). Questo non ti dice nulla sugli effetti collaterali. Controllare l'orologio di sistema non è un effetto collaterale; in effetti, qualsiasi funzione o metodo con il prefisso "get" è uno che dovresti ragionevolmente aspettarti di non avere effetti collaterali.
Aaronaught,

36

Si dice che qualsiasi operazione che modifica lo stato del computer o che interagisce con il mondo esterno abbia un effetto collaterale. Vedi Wikipedia su effetti collaterali .

Ad esempio, questa funzione non ha effetti collaterali. Il suo risultato dipende solo dai suoi argomenti di input e nulla sullo stato del programma o del suo ambiente cambia quando viene chiamato:

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

Al contrario, chiamare queste funzioni ti darà risultati diversi a seconda dell'ordine in cui le chiami, perché cambiano qualcosa sullo stato del computer:

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

Questa funzione ha l'effetto collaterale di scrivere dati sull'output. Non si chiama la funzione perché si desidera il suo valore di ritorno; lo chiami perché vuoi l'effetto che ha sul "mondo esterno":

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

1
Questa è una buona definizione, ma non vado pazzo per l'elaborazione - proprio come nella risposta di Thorbjørn, parte di essa sembra fondere il problema degli effetti collaterali con quello delle funzioni idempotenti; come Writedimostra il tuo esempio, avere effetti collaterali non implica che la funzione cambi mai il suo output rispetto ai suoi input, o anche che il suo output dipenda dall'input.
Aaronaught,

6
Non si tratta di essere idempotenti. Il fatto che produca output significa che ha un effetto collaterale.
Kristopher Johnson,

In alcuni sistemi, il richiamo square(x)potrebbe causare il caricamento dal disco del modulo in cui è definita la funzione. Questo dovrebbe essere considerato un effetto collaterale? Dopotutto, questo uomo che la (prima) chiamata impiega inaspettatamente a lungo, che l'utilizzo della RAM aumenta, ecc.
Hagen von Eitzen,

1
@HagenvonEitzen Ogni operazione apporta effettivamente modifiche allo stato del computer (registri della CPU, memoria, consumo di energia, calore, ecc.). "Effetto collaterale" di solito si riferisce a un immaginario ambiente di esecuzione idealizzato in cui nulla di tale ambiente cambia a meno che il programma non lo cambi esplicitamente. Ma se stai chiamando square(x) perché vuoi che lo stato di un computer esterno cambi, potresti considerare che si tratta di un effetto collaterale.
Kristopher Johnson,

Per me la prima illustrazione ha perfettamente senso. Tuttavia, il secondo in meno. Credo che l'effetto collaterale debba essere definito in relazione a un determinato ambiente / ambito. Se consideri l'intero universo, non esiste alcun effetto collaterale. Anche se lo limiti al computer, la tua funzione influenzerà altri processi in quanto la CPU non si comporterà allo stesso modo. Se limiti l'ambito alle cose accessibili nell'ambito di una funzione locale, allora abbiamo qualcosa di cui parlare.
funct7

21

Penso che le risposte esistenti siano abbastanza buone. Vorrei approfondire alcuni aspetti che l'IMO non è stato sottolineato abbastanza.

In matematica una funzione è solo una mappatura da una tupla di valori a un valore. Quindi, data una funzione fe un valore x, f(x)sarà sempre lo stesso risultato y. Puoi benissimo sostituirlo f(x)con yovunque in un'espressione e nulla cambierà.

Quella che viene chiamata una funzione (o procedura) in molti linguaggi di programmazione è un costrutto (pezzo di codice) che può essere eseguito perché:

  1. Calcola una funzione in senso matematico, ovvero dati valori di input, restituisce un risultato o
  2. Produce qualche effetto, ad esempio stampa qualcosa sullo schermo, cambia un valore su un database, lancia missili, dorme per 10 secondi, invia un SMS.

Quindi gli effetti possono essere correlati allo stato ma anche ad altri aspetti come sparare un missile o mettere in pausa l'esecuzione per alcuni secondi.

Il termine effetto collaterale può sembrare negativo ma normalmente l'effetto di chiamare una funzione è lo scopo stesso della funzione stessa. Suppongo che, dal momento che il termine funzione era originariamente utilizzato in matematica, il calcolo di un valore è considerato l' effetto principale di una funzione, mentre qualsiasi altro effetto è considerato effetti collaterali . Alcuni linguaggi di programmazione usano il termine procedura per evitare confusione con le funzioni in senso matematico.

Nota che

  1. Alcune procedure sono utili sia per il loro valore di ritorno che per i loro effetti collaterali.
  2. Alcune procedure calcolano solo un valore di risultato e non hanno altri effetti. Spesso vengono chiamate funzioni pure perché tutto ciò che fanno è calcolare una funzione in senso matematico.
  3. Alcune procedure, ad esempio sleep()in Python, sono utili solo per i loro effetti (collaterali),. Questi sono spesso modellati come funzioni che restituiscono un valore speciale None, o unito ()o ..., che indica semplicemente che il calcolo è terminato correttamente.

2
Secondo la mia modesta opinione, questa dovrebbe essere la risposta accettata. Il concetto di effetto collaterale ha anche senso solo in termini di funzioni matematiche. Una procedura è progettata per raggruppare semplicemente un set di istruzioni in modo strutturato, consentendo al contempo di passare a quel set da qualsiasi luogo e ritorno comodamente. Non ci sono effetti primari e collaterali. Potresti forse dire che lanciare un'eccezione è un effetto collaterale di una procedura, in quanto interrompe l'intento della procedura che è di riportarti al punto in cui ti eri interrotto e continuare l'esecuzione da lì.
Didier A.

4

Un effetto collaterale è quando un'operazione ha un effetto su una variabile / oggetto al di fuori dell'uso previsto.

Può accadere quando si effettua una chiamata a una funzione complessa che ha un effetto collaterale di alterazione di una variabile globale, anche se non era questo il motivo per cui l'hai chiamata (forse l'hai chiamata per estrarre qualcosa da un database).

Devo ammettere che sto avendo problemi a trovare un semplice esempio che non sembra del tutto inventato, e gli esempi di cose su cui ho lavorato sono troppo lunghi per essere pubblicati qui (e dal momento che sono legati al lavoro, probabilmente non dovrei comunque ).

Un esempio che ho visto (qualche tempo fa) era una funzione che apriva una connessione al database se la connessione era in uno stato chiuso. Il problema era che avrebbe dovuto chiudere la connessione alla fine della funzione, ma lo sviluppatore ha dimenticato di aggiungere quel codice. Quindi qui, c'era un effetto collaterale non intenzionale : la chiamata a una procedura avrebbe dovuto solo fare una query e l'effetto collaterale era che la connessione rimaneva aperta e se la funzione veniva chiamata due volte di seguito, si sarebbe generato un errore dicendo che la connessione era già aperto.


Ok, quindi dato che adesso tutti danno esempi, penso che lo farò anch'io;)

/*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;

La funzione do_task_xha un effetto primario nel restituire il risultato di alcuni calcoli e un effetto collaterale della possibile modifica di una variabile globale.

Naturalmente, qual è il principale e quale è l'effetto collaterale potrebbe essere aperto all'interpretazione e potrebbe dipendere dall'uso effettivo. Se chiamo questa funzione allo scopo di modificare il globale e scarto il valore restituito di quanto direi che la modifica del globale è l'effetto principale.


2
Non penso che questa sia una buona definizione universale. Molti programmatori usano intenzionalmente costrutti appositamente per i loro effetti collaterali.
CB Bailey,

@Charles: abbastanza giusto. In tal caso, come lo definiresti?
FrustratedWithFormsDesigner,

2
Penso che @KristopherJohnson abbia la definizione più chiara. Tutto ciò che altera lo stato del programma o il suo ambiente o produce un effetto reale come la generazione di output.
CB Bailey,

@Charles Bailey: questo non cambia la definizione. Usare le cose per l'effetto collaterale va bene. Finché capisci che c'è un effetto collaterale. Non altera nulla di questa definizione.
S. Lott,

1
@SLott: la definizione in questa risposta (ovvero il primo paragrafo) include la clausola: "al di fuori dell'uso previsto". Penso che il mio commento sia stato giusto.
CB Bailey,

3

Nell'informatica, si dice che una funzione o espressione abbia un effetto collaterale se modifica uno stato o ha un'interazione osservabile con le funzioni di chiamata o il mondo esterno.

Da Wikipedia - Effetto collaterale

Una funzione, in senso matematico, è una mappatura da input a output. L'effetto previsto del richiamo di una funzione è di mappare l'input sull'output che restituisce. Se la funzione fa qualcos'altro, non importa cosa, ma se ha un comportamento che non sta mappando l'input sull'output, quel comportamento è noto per essere un effetto collaterale.

In termini più generali, un effetto collaterale è qualsiasi effetto che non è l'effetto previsto dal progettista del costrutto.

Un effetto è tutto ciò che colpisce un attore. Se chiamo una funzione che invia alla mia fidanzata un messaggio di errore, che riguarda un gruppo di attori, io, lei, la rete della compagnia di telefonia cellulare, ecc. L'unico effetto previsto di chiamare una funzione gratuita con effetti collaterali è per la funzione per restituirmi una mappatura dal mio input. Quindi per:

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

Se si intende che questa sia una funzione, l'unica cosa che dovrebbe fare è restituire il vuoto. Se fosse privo di effetti collaterali, non dovrebbe effettivamente inviare il messaggio di testo.

Nella maggior parte dei linguaggi di programmazione, non esiste un costrutto per una funzione matematica. Nessun costrutto deve essere usato come tale. Ecco perché la maggior parte delle lingue afferma che hai metodi o procedure. In base alla progettazione, si intende che questi siano in grado di produrre molti più effetti. Nel linguaggio comune della programmazione, a nessuno interessa davvero l'intento di quale sia stato un metodo o una procedura, quindi quando qualcuno dice che questa funzione ha effetti collaterali, significa effettivamente che questo costrutto non si comporta come una funzione matematica. E quando qualcuno dice che questa funzione è priva di effetti collaterali, significa che questo costrutto si comporta efficacemente come una funzione matematica.

Una funzione pura è sempre priva di effetti collaterali, per definizione. Una funzione pura, è un modo di dire, questa funzione, anche se sta usando un costrutto che consente più effetti, ha come effetto uguale a quello di una funzione matematica.

Sfido chiunque a dirmi quando una funzione senza effetti collaterali non sarebbe pura. A meno che l'effetto primario voluto del contesto della frase usando il termine puro e senza effetti collaterali non sia quello dell'effetto matematico previsto di una funzione, allora questi sono sempre uguali.

Come tale, a volte, anche se più raramente, e credo che questa sia la distinzione che manca e guida erroneamente le persone (in quanto ciò non è il presupposto più comune) nella risposta accettata, ma a volte si presume che l'effetto previsto di una funzione di programmazione sia mappare l'input sull'output, dove l'input non è vincolato ai parametri espliciti della funzione, ma l'output è vincolato al valore di ritorno esplicito. Se supponi che sia l'effetto desiderato, una funzione che legge un file e restituisce un risultato diverso in base a ciò che è nel file è ancora priva di effetti collaterali, poiché hai permesso agli input di provenire da altri punti dell'effetto desiderato.

Quindi, perché è tutto così importante?

Si tratta di controllo e mantenimento. Se chiamate una funzione e fa qualcos'altro, quindi restituisce un valore, è difficile ragionare sul suo comportamento. Dovrai andare all'interno della funzione per individuare il codice effettivo per indovinare cosa sta facendo e affermarne la correttezza. La situazione ideale è che è molto chiaro e facile sapere qual è l'input utilizzato dalla funzione e che non sta facendo altro che restituire un output per esso. Puoi rilassare un po 'questo, e dire che sapere esattamente quale input sta usando non è utile quanto essere certo che non sta facendo altro che potresti non essere a conoscenza e quindi restituire un valore, quindi forse sei soddisfatto solo di far rispettare che non fa nient'altro che mappare l'input, indipendentemente da dove lo ottiene, all'output.

In quasi tutti i casi, il punto di un programma è avere effetti diversi dalla mappatura delle cose che entrano nelle cose che escono. L'idea di controllare l'effetto collaterale è che puoi organizzare il codice in un modo che sia più facile da capire e ragionare. Se metti insieme tutti gli effetti collaterali, in un posto che è molto esplicito e centrale, è facile sapere dove guardare e fidarsi che questo è tutto ciò che sta accadendo, non di più. Se l'input è anche molto esplicito, aiuta a testare il comportamento per input diversi ed è più facile da usare, poiché non è necessario modificare l'input in molti luoghi diversi, alcuni dei quali potrebbero non essere ovvi, solo per ottenere quello che vuoi.

Poiché il più utile per capire, ragionare e controllare il comportamento di un programma è avere tutti gli input chiaramente raggruppati ed espliciti, così come avere tutti gli effetti collaterali essere raggruppati ed espliciti, questo è generalmente ciò di cui le persone parlano quando dicono effetto collaterale, puro, ecc.

Poiché il più utile è il raggruppamento degli effetti collaterali e la loro esplicitazione, a volte le persone intendono solo questo, e lo distinguono dicendo che non è puro, ma è ancora "effetto collaterale" libero. Ma l'effetto collaterale è relativo al presunto "effetto primario previsto", quindi è un termine contestuale. Trovo che questo sia usato meno spesso, anche se sorprendentemente si parla molto di questo thread.

Infine, idempotente significa che chiamare questa funzione più volte con gli stessi input (non importa da dove vengano) provocherà sempre gli stessi effetti (effetto collaterale o meno).


Penso che un grosso problema con la spiegazione degli effetti collaterali sia che fino a quando non usi un linguaggio come Ocaml o Haskell, può essere molto difficile ragionare sulla programmazione libera (quasi!) Degli effetti collaterali.
Jamie Strauss,

2

Nella programmazione di un effetto collaterale si verifica quando una procedura cambia una variabile al di fuori del suo ambito. Gli effetti collaterali non dipendono dalla lingua. Ci sono alcune classi di linguaggi che mirano ad eliminare gli effetti collaterali (linguaggi funzionali puri), ma non sono sicuro se ce ne siano alcuni che richiedono effetti collaterali, ma potrei sbagliarmi.

Per quanto ne so, non ci sono effetti collaterali interni ed esterni.


Per essere più precisi, i linguaggi funzionali puri separano chiaramente il codice libero dagli effetti collaterali da altri codici, mentre altre lingue non hanno alcun meccanismo per distinguere tra codice puro e codice impuro. La maggior parte dei programmi deve avere effetti collaterali per essere di qualsiasi utilità.
Giorgio,

Penso che alcuni dei linguaggi di programmazione pre-gui come MS-BASIC e QBasic potrebbero essere stati il ​​più vicino possibile ad un linguaggio "solo effetto collaterale". E sì, puoi avere effetti collaterali sia interni che esterni.
James K,

0

Qui c'è un semplice esempio:

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

La definizione di effetto collaterale non è specifica per la programmazione, quindi immagina semplicemente gli effetti collaterali dei tuoi farmaci o mangia troppo cibo.


Ma se il messaggio arriva come riferimento e cambi messaggio nel tuo metodo, ciò potrebbe essere un effetto collaterale. Ho ragione?
Amir Rezaei,

Il fatto che l'espressione x++modifichi la variabile xè comunemente considerato un effetto collaterale. Quel valore dell'espressione è il valore pre-incremento di x; questa è la parte dell'effetto non collaterale dell'espressione.
CB Bailey,

@Charles - Sono d'accordo, anche se l'esempio originale non era chiaro come quello attuale.
ChaosPandion,

@Amir - Beh, dipende molto dalla lingua. Se questo fosse C # questo non sarebbe considerato un effetto collaterale.
ChaosPandion,

@ChaosPandion: Personalmente, non sono d'accordo. L'esempio originale era molto più semplice e chiaro.
CB Bailey,

-2

Un effetto collaterale è ciò che accade nel codice che non è evidente.

Ad esempio, supponiamo che tu abbia questa classe

public class ContrivedRandomGenerator {
   public int Seed { get; set; }

   public int GetRandomValue()
   {
      Random(Seed);
      Seed++;
   }
}

Quando inizialmente crei la classe, le dai un seme.

var randomGenerator = new ContrivedRandomGenerator();
randomGenerator.Seed = 15;
randomGenerator.GetRandomValue();

Non conosci gli interni, ti aspetti di ottenere un valore casuale e ti aspetteresti che randomGenerator abbia ancora 15 anni ... ma non lo è.

La chiamata di funzione ha avuto l'effetto collaterale di cambiare il valore del seme.


10
Gli effetti collaterali non devono essere nascosti. Stai pensando di uso colloquiale o medico; nella programmazione, un effetto collaterale si riferisce semplicemente alla modifica di alcuni stati.
Aaronaught,

1
La stampa sulla console è un effetto collaterale. Non è nascosto. Da Wikipedia : "Nell'informatica si dice che una funzione o espressione abbia un effetto collaterale se, oltre a restituire un valore, modifica anche un certo stato o ha un'interazione osservabile con le funzioni di chiamata o il mondo esterno ".

Gli effetti collaterali sono come le non funzioni (ovvero le procedure) eseguono qualsiasi lavoro. X = 1; X = Y (10) sono due funzioni pure. Quando esci dal regno "x = qualunque cosa", se scrivere l'output sullo schermo | drive | printer | led o leggere l'input all'esterno del formato "x = y" o semplicemente cambiare il valore di una variabile da una cosa all'altra , è un effetto collaterale.
James K,

Penso che per "nascosto" significhi non ovvio. Come in x = f (y, z) si può presumere che x sia basato su y e z. Considerando che proc (x, y, z) non dice nulla su ciò che sta succedendo. Ogni variante può essere modificata o nessuna. Proc potrebbe essere un analogo di f, o completamente non correlato. Una funzione pura ha una sola risposta: 'x'. Vai oltre, è un effetto collaterale. Interamente inteso, ma effetti collaterali.
James K,

Proprio come per capire 0, devi prima capire 1: Per capire gli effetti collaterali devi prima capire le funzioni.
James K,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.