O que é um "efeito colateral"?

88

Não entendi claramente o conceito de efeito colateral.

  • Qual é o efeito colateral da programação?
  • É dependente da linguagem de programação?
  • Existe efeitos colaterais externos e internos?

Por favor, dê um exemplo de causas que criam efeitos colaterais.

Amir Rezaei
fonte
7
Soa muito como lição de casa.
precisa saber é o seguinte
3
@ gnasher729 quem se importa este é tremendamente útil :)
Charlie Parker

Respostas:

108

Um efeito colateral refere-se simplesmente à modificação de algum tipo de estado - por exemplo:

  • Alterando o valor de uma variável;
  • Gravando alguns dados em disco;
  • Ativando ou desativando um botão na interface do usuário.

Ao contrário do que algumas pessoas parecem estar dizendo:

  • Um efeito colateral não precisa ser oculto ou inesperado (pode ser, mas isso não tem nada a ver com a definição que se aplica à ciência da computação);

  • Um efeito colateral não tem nada a ver com idempotência. Uma função idempotente pode ter efeitos colaterais, e uma função não idempotente pode não ter efeitos colaterais (como obter a data e hora atuais do sistema).

É realmente muito simples. Efeito colateral = mudar algo em algum lugar.

PS Como comenta Benjol, várias pessoas podem estar confundindo a definição de um efeito colateral com a definição de uma função pura , que é uma função que é (a) idempotente e (b) não tem efeitos colaterais. Um não implica o outro na ciência geral da computação, mas as linguagens de programação funcional tendem a impor as duas restrições.

Aaronaught
fonte
38
A frase "efeito colateral" faz parecer que outra coisa está sendo alterada, além do que foi planejado. Na medicina, um medicamento tem um efeito principal de reduzir a dor e, às vezes, um efeito colateral de causar sangramento nasal, tontura, etc ... o objetivo do medicamento não é causar sangramento nasal, mas às vezes isso acontece como resultado extra não intencional .
FrustratedWithFormsDesigner
15
@ Frustrado: +1. Sempre que vejo esse termo, não posso deixar de me perguntar se não foi escolhido pelos advogados da FP para criar precisamente essa conotação sutilmente sinistra.
Mason Wheeler
6
@Mason Wheeler. Já existia muito antes da FP. E não é uma conotação sutilmente sinistra. É um mal direto e sempre foi. Nas três décadas em que codifiquei, a declaração de "atribuição de criptografia" - o efeito colateral - tem incomodado as pessoas. Uma declaração de atribuição antiga simples é muito mais fácil de lidar.
precisa saber é o seguinte
7
@ Wheeler Mason: Em C ++a.. Não parece tarefa. b = ++a;tem dois efeitos colaterais. O óbvio e a atribuição de criptografia de a. Esse é o tipo de coisa que é um efeito colateral que (para alguns) é desejável. Mas isso foi chamado de efeito colateral de toda a minha carreira para torná-la não sutil.
precisa saber é o seguinte
5
@ Zachary, veja o último marcador na minha resposta. O que você está se referindo é um comportamento idempotente (ou a falta dele). Isso não diz nada sobre os efeitos colaterais. Verificar o relógio do sistema não é um efeito colateral; de fato, qualquer função ou método prefixado com a palavra "get" é aquele que você razoavelmente espera que não tenha efeitos colaterais.
Aaronaught
36

Diz-se que qualquer operação que modifique o estado do computador ou que interaja com o mundo exterior tem um efeito colateral. Veja a Wikipedia sobre efeitos colaterais .

Por exemplo, esta função não tem efeitos colaterais. Seu resultado depende apenas dos argumentos de entrada e nada sobre o estado do programa ou seu ambiente muda quando é chamado:

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

Por outro lado, chamar essas funções fornecerá resultados diferentes, dependendo da ordem em que você as chama, porque elas alteram algo sobre o estado do computador:

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

Esta função tem o efeito colateral de gravar dados na saída. Você não chama a função porque deseja seu valor de retorno; você o chama porque deseja o efeito que ele tem no "mundo exterior":

int Write(const char* s) { return printf("Output: %s\n", s); }
Kristopher Johnson
fonte
1
Essa é uma boa definição, mas não sou louca pela elaboração - assim como na resposta de Thorbjørn, parte dela parece estar confluindo a questão dos efeitos colaterais com a das funções idempotentes; como seu Writeexemplo demonstra, ter efeitos colaterais não implica que a função mude sua saída em relação a suas entradas, ou mesmo que sua saída dependa da entrada.
Aaronaught
6
Não se trata de ser idempotente. O fato de produzir resultados significa que tem um efeito colateral.
Kristopher Johnson
Em alguns sistemas, a chamada square(x)pode fazer com que o módulo em que a função está definida seja carregado do disco. Isso deve ser considerado efeito colateral? Afinal, esta mens que o (primeiro) chamada leva inesperadamente longo, que o uso da RAM sobe, etc.
Hagen von Eitzen
1
@HagenvonEitzen Todas as operações efetivamente alteram o estado do computador (registros da CPU, memória, consumo de energia, calor, etc.). "Efeito colateral" geralmente se refere a um ambiente de execução idealizado imaginário em que nada nesse ambiente muda, a menos que o programa o altere explicitamente. Mas se você estiver ligando square(x) porque deseja que o estado do computador externo mude, considere isso como um efeito colateral.
21317 Kristoff Johnson
Para mim, a primeira ilustração faz todo sentido. No entanto, o segundo menos. Eu acredito que o efeito colateral deve ser definido em relação a um determinado ambiente / escopo. Se você considera o universo inteiro, não existe efeito colateral. Mesmo se você o limitar ao computador, sua função afetará outros processos, pois a CPU não se comportará da mesma maneira. Se você limitar o escopo às coisas acessíveis em um escopo de função local, teremos algo para conversar.
funct7 14/10
21

Eu acho que as respostas existentes são muito boas. Gostaria de elaborar alguns aspectos que a OMI não foi enfatizada o suficiente.

Em matemática, uma função é apenas um mapeamento de uma tupla de valores para um valor. Portanto, dada uma função fe um valor x, f(x)sempre será o mesmo resultado y. Você pode substituir f(x)por ytodos os lugares de uma expressão e nada mudará.

O que é chamado de função (ou procedimento) em muitas linguagens de programação é uma construção (parte do código) que pode ser executada porque:

  1. Ele calcula uma função no sentido matemático, ou seja, dados os valores de entrada, retorna um resultado ou
  2. Produz algum efeito, por exemplo, imprime algo na tela, altera um valor em um banco de dados, lança mísseis, dorme por 10 segundos, envia um SMS.

Portanto, os efeitos podem estar relacionados ao estado, mas também a outros aspectos, como disparar um míssil ou pausar a execução por alguns segundos.

O termo efeito colateral pode parecer negativo, mas normalmente o efeito de chamar uma função é o próprio objetivo da própria função. Suponho que, como o termo função foi originalmente usado em Matemática, a computação de um valor seja considerada o efeito primário de uma função, enquanto outros efeitos são considerados efeitos colaterais . Algumas linguagens de programação usam o termo procedimento para evitar confusões com funções no sentido matemático.

Observe que

  1. Alguns procedimentos são úteis tanto para o valor de retorno quanto para o efeito colateral.
  2. Alguns procedimentos calculam apenas um valor de resultado e não têm outros efeitos. Eles são freqüentemente chamados de funções puras, porque tudo o que fazem é computar uma função no sentido matemático.
  3. Alguns procedimentos, por exemplo, sleep()em Python, são úteis apenas para seus efeitos (colaterais),. Eles geralmente são modelados como funções que retornam um valor especial None, ou unitou ()ou ..., o que simplesmente indica que o cálculo foi finalizado corretamente.
Giorgio
fonte
2
Na minha humilde opinião, essa deve ser a resposta aceita. O conceito de efeito colateral só faz sentido em termos de funções matemáticas. Um procedimento foi projetado para simplesmente agrupar um conjunto de instruções de maneira estruturada, permitindo que você pule para esse conjunto de qualquer lugar e volte convenientemente. Não há efeito primário pretendido e efeitos colaterais. Você pode dizer que lançar uma exceção é um efeito colateral de um procedimento, pois ele interrompe a intenção do procedimento, que é direcioná-lo de volta para onde você parou e continuar o formulário de execução.
Didier A.
4

Um efeito colateral é quando uma operação afeta uma variável / objeto que está fora do uso pretendido.

Isso pode acontecer quando você faz uma chamada para uma função complexa que tem o efeito colateral de alterar alguma variável global, mesmo que não tenha sido o motivo pelo qual você a chamou (talvez você tenha chamado para extrair algo de um banco de dados).

Eu admito que estou tendo problemas para apresentar um exemplo simples que não parece totalmente artificial, e exemplos de coisas nas quais trabalhei são muito longos para serem postados aqui (e, como é relacionado ao trabalho, provavelmente não devo )

Um exemplo que eu vi (há algum tempo) foi uma função que abriu uma conexão com o banco de dados se a conexão estivesse em um estado fechado. O problema era que ele deveria fechar a conexão no final da função, mas o desenvolvedor esqueceu de adicionar esse código. Portanto, aqui havia um efeito colateral não intencional : chamar um procedimento deveria fazer apenas uma consulta e o efeito colateral era que a conexão permanecesse aberta e se a função fosse chamada duas vezes seguidas, seria gerado um erro dizendo que a conexão era já aberto.


Ok, então como todo mundo está dando exemplos agora, acho que vou também;)

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

A função do_task_xtem um efeito primário de retornar o resultado de alguns cálculos e um efeito colateral de possivelmente modificar uma variável global.

Obviamente, qual é o principal e qual é o efeito colateral pode estar aberto à interpretação e depender do uso real. Se eu chamar essa função com a finalidade de modificar o global e descartar o valor retornado, diria que modificar o global é o efeito principal.

FrustratedWithFormsDesigner
fonte
2
Não acho que essa seja uma boa definição universal. Muitos programadores intencionalmente usam construções especificamente para seus efeitos colaterais.
CB Bailey
@ Charles: Justo o suficiente. Nesse caso, como você o definiria?
FrustratedWithFormsDesigner
2
Eu acho que @KristopherJohnson tem a definição mais clara. Qualquer coisa que altere o estado do programa ou seu ambiente ou produza um efeito no mundo real, como gerar saída.
CB Bailey
@ Charles Bailey: Isso não muda a definição. Usar coisas para o efeito colateral é bom. Contanto que você entenda que há um efeito colateral. Não altera nada sobre essa definição.
precisa saber é o seguinte
1
@ Slott: A definição nesta resposta (ou seja, o primeiro parágrafo) inclui a cláusula: "fora do uso pretendido". Eu acho que meu comentário foi justo.
CB Bailey
3

Na ciência da computação, diz-se que uma função ou expressão tem um efeito colateral se modificar algum estado ou se houver uma interação observável com as funções de chamada ou com o mundo exterior.

Da Wikipedia - Efeito Colateral

Uma função, no sentido matemático, é um mapeamento da entrada para a saída. O efeito pretendido de chamar uma função é mapear a entrada para a saída que retorna. Se a função fizer qualquer outra coisa, não importa o quê, mas se tiver algum comportamento que não esteja mapeando a entrada para a saída, esse comportamento é conhecido por ser um efeito colateral.

Em termos mais gerais, um efeito colateral é qualquer efeito que não seja o efeito pretendido pelo projetista da construção.

Um efeito é qualquer coisa que afeta um ator. Se eu ligar para uma função que envie à minha namorada uma mensagem de texto final, que afete vários atores, eu, ela, a rede da empresa de telefonia celular etc. O único efeito pretendido de chamar uma função livre de efeito colateral é a função para retornar um mapeamento da minha entrada. Então para:

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

Se isso pretende ser uma função, a única coisa que deve fazer é retornar nulo. Se fosse livre de efeitos colaterais, não deveria realmente enviar a mensagem de texto.

Na maioria das linguagens de programação, não há construção para uma função matemática. Nenhuma construção se destina a ser usada como tal. É por isso que a maioria dos idiomas diz que você tem métodos ou procedimentos. Por design, esses itens devem ter muito mais efeitos. Na linguagem comum de programação, ninguém realmente se importa com a intenção de qual método ou procedimento era; portanto , quando alguém diz que essa função tem efeito colateral, eles efetivamente significam que esse construto não se comporta como uma função matemática. E quando alguém diz que essa função é livre de efeitos colaterais, eles querem dizer que esse construto se comporta efetivamente como uma função matemática.

Uma função pura é sempre livre de efeitos colaterais, por definição. Uma função pura, é uma maneira de dizer, essa função, mesmo que esteja usando uma construção que permita mais efeitos, tem como efeito igual à de uma função matemática.

Eu desafio alguém a me dizer quando uma função livre de efeitos colaterais não seria pura. A menos que o efeito primário pretendido do contexto da sentença usando o termo puro e livre de efeitos colaterais não seja o efeito matemático de uma função, eles sempre serão iguais.

Como tal, às vezes, embora mais raramente, e acredito que essa é a distinção que falta e também desorienta as pessoas (como essa não é a suposição mais comum) na resposta aceita, mas às vezes presume-se que o efeito pretendido de uma função de programação seja mapear entrada para saída, em que a entrada não é restrita aos parâmetros explícitos da função, mas a saída é restrita ao valor de retorno explícito. Se você assumir que esse é o efeito pretendido, uma função que esteja lendo um arquivo e retornando um resultado diferente com base no que está no arquivo ainda estará livre de efeitos colaterais, pois você permitiu que entradas fossem provenientes de outros lugares no efeito pretendido.

Então, por que tudo isso é importante?

É tudo sobre controle e manutenção. Se você chama uma função e ela faz outra coisa e depois retorna um valor, é difícil argumentar sobre seu comportamento. Você precisará procurar dentro da função o código real para adivinhar o que está fazendo e afirmar sua correção. A situação ideal é que é muito claro e fácil saber qual é a entrada que a função está usando e que ela não está fazendo nada além de retornar uma saída para ela. Você pode relaxar um pouco e dizer que saber exatamente qual entrada está sendo usada não é tão útil quanto ter certeza de que não está fazendo mais nada do que você talvez não esteja ciente de retornar um valor, então talvez esteja satisfeito apenas em aplicar que ele não faz mais nada, em seguida, mapeia a entrada, não importa de onde vem, para a saída.

Em quase todos os casos, o objetivo de um programa é ter efeitos que não sejam mapear as coisas que vão surgindo. A idéia de controlar o efeito colateral é que você pode organizar o código de uma maneira que seja mais fácil de entender e raciocinar. Se você reunir todo o efeito colateral, em um local muito explícito e central, é fácil saber para onde procurar e confiar que isso é tudo o que está acontecendo, nada mais. Se você tem uma entrada muito explícita, isso ajuda a testar o comportamento de entradas diferentes e é mais fácil de usar, pois você não precisa alterar a entrada em muitos lugares diferentes, alguns que podem não ser óbvios, apenas para conseguir o que você quer.

Como o mais útil para entender, raciocinar e controlar o comportamento de um programa é ter todas as entradas claramente agrupadas e explícitas, além de todos os efeitos colaterais serem agrupados e explícitos, é sobre isso que as pessoas falam quando dizem efeito colateral, puro, etc.

Como o mais útil é o agrupamento dos efeitos colaterais e sua explicitação, às vezes as pessoas apenas querem dizer isso, e o distinguem dizendo que não é puro, mas ainda é "livre de efeitos colaterais". Mas efeito colateral é relativo ao suposto "efeito primário pretendido", portanto é um termo contextual. Acho que isso é usado com menos frequência, embora, surpreendentemente, seja discutido muito neste tópico.

Por fim, idempotente significa chamar essa função muitas vezes com as mesmas entradas (não importa de onde elas venham) sempre resultará nos mesmos efeitos (efeito colateral ou não).

Didier A.
fonte
Acho que um grande problema para explicar os efeitos colaterais é que, até que você use uma linguagem como Ocaml ou Haskell, pode ser muito difícil argumentar sobre a programação livre de efeitos colaterais (quase!).
21319 Jamie Strauss
2

Na programação, um efeito colateral é quando um procedimento altera uma variável de fora do seu escopo. Os efeitos colaterais não dependem do idioma. Existem algumas classes de idiomas que visam eliminar efeitos colaterais (idiomas funcionais puros), mas não tenho certeza se há algum que exija efeitos colaterais, mas posso estar errado.

Tanto quanto eu sei, não há efeitos colaterais internos e externos.

indyK1ng
fonte
Para ser mais preciso, as linguagens funcionais puras separam claramente o código livre de efeitos colaterais de outro código, enquanto outros idiomas não têm mecanismo para distinguir entre código puro e impuro. A maioria dos programas precisa ter efeitos colaterais para ter alguma utilidade.
Giorgio
Eu acho que algumas das linguagens de programação pré-GUI, como o MS-BASIC e o QBasic, podem ter sido tão próximas de uma linguagem de 'apenas efeito colateral' quanto possível. E sim, você pode ter efeitos colaterais internos e externos.
James K
0

Aqui está um exemplo simples:

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

A definição de efeito colateral não é específica da programação; basta imaginar os efeitos colaterais dos remédios ou comer muita comida.

ChaosPandion
fonte
Mas se a mensagem chegar como referência e você alterar a mensagem no seu método, isso poderá ser um efeito colateral. Estou correcto?
Amir Rezaei 26/01
O fato de a expressão x++modificar a variável xé geralmente considerado um efeito colateral. Esse valor da expressão é o valor de pré-incremento de x; essa é a parte do efeito não colateral da expressão.
CB Bailey
@ Charles - eu concordo, embora o exemplo original não tenha sido tão claro quanto o atual.
precisa saber é o seguinte
@Amir - Bem, isso realmente depende do idioma. Se fosse C #, isso não seria considerado um efeito colateral.
precisa saber é o seguinte
@ChaosPandion: Pessoalmente, eu discordo. O exemplo original era muito mais simples e claro.
CB Bailey
-2

Um efeito colateral são coisas que acontecem no código que não são obviamente aparentes.

Por exemplo, digamos que você tenha essa classe

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

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

Quando você cria a classe inicialmente, dá a ela uma semente.

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

Você não conhece os internos, apenas espera obter um valor aleatório e esperaria que o randomGenerator.Seed ainda tivesse 15 ... mas não é.

A chamada de função teve o efeito colateral de alterar o valor de propagação.

CaffGeek
fonte
10
Os efeitos colaterais não precisam ser ocultados. Você está pensando em uso coloquial ou médico; na programação, um efeito colateral simplesmente se refere à modificação de algum estado.
Aaronaught
1
Imprimir no console é um efeito colateral. Não está oculto. Da Wikipedia : "Na ciência da computação, uma função ou expressão tem um efeito colateral se, além de retornar um valor, ela também modifica algum estado ou tem uma interação observável com as funções de chamada ou com o mundo exterior ".
Os efeitos colaterais são como as não funções (procedimentos) executam qualquer trabalho. X = 1; X = Y (10) são duas funções puras. Quando você sai da região "x = seja qual for", se deseja gravar a saída na tela | drive | impressora | conduzida ou ler a entrada fora do formato "x = y" ou simplesmente alterar o valor de uma variável de uma coisa para outra , é um efeito colateral.
James K
Eu acho que por 'escondido', ele quer dizer não óbvio. Como em x = f (y, z), x pode ser considerado baseado em y e z. Enquanto proc (x, y, z) não diz nada sobre o que está acontecendo. Cada variável pode ser alterada ou nenhuma. Proc pode ser um análogo a f ou completamente não relacionado. Uma função pura tem uma única resposta: 'x'. Vá além disso, é um efeito colateral. Totalmente intencionado, mas com efeitos colaterais.
James K
Assim como entender 0, primeiro você deve entender 1: Para entender os efeitos colaterais, você deve entender primeiro as funções.
James K