it-swarm.it

Che cos'è un "effetto collaterale"?

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.

101
Amir Rezaei

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.

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

114
Aaronaught

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 Side Effect .

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); }
38

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 f e un valore x, f(x) sarà sempre lo stesso risultato y. È possibile sostituire f(x) con y ovunque 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 es. stampa qualcosa sullo schermo, modifica 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 come effetto primario 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 es. sleep() in Python, sono utili solo per i loro effetti (collaterali),. Questi sono spesso modellati come funzioni che restituiscono un valore speciale None o unit o () o ..., che indica semplicemente che il calcolo è terminato correttamente.
24
Giorgio

Un effetto collaterale è quando un'operazione ha un effetto su una variabile/oggetto che è 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 si è dimenticato di aggiungere quel codice. Quindi qui, c'era un effetto collaterale involontario : la chiamata a una procedura doveva fare solo una query e l'effetto collaterale era che la connessione rimaneva aperta e se la funzione è stata chiamata due volte di seguito, verrebbe generato un errore dicendo che la connessione era già aperta.


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_x ha un effetto primario di restituire il risultato di alcuni calcoli e un effetto lato della possibile modifica di una variabile globale.

Naturalmente, quale è 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.

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 della chiamata di una funzione è di mappare l'input sull'output che restituisce. Se la funzione fa qualcos'altro, non importa cosa, ma se ha qualche 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. Così 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'intenzione di quale sia stato un metodo o una procedura, quindi quando qualcuno dice che questa funzione ha effetti collaterali, significa effettivamente, 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 rilassarlo un po 'e dire che sapere esattamente quale input sta utilizzando non è utile quanto essere certo che non sta facendo altro che potresti non essere a conoscenza di cui potresti 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).

3
Didier A.

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.

2
indyK1ng

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.

0
ChaosPandion