¿Qué es un "efecto secundario"?

88

No he entendido claramente el concepto de efecto secundario.

  • ¿Qué es el efecto secundario en la programación?
  • ¿Es dependiente del lenguaje de programación?
  • ¿Existen los efectos secundarios externos e internos?

Dé un ejemplo de las causas que crean efectos secundarios.

Amir Rezaei
fuente
77
Suena muy parecido a la tarea.
gnasher729
3
@ gnasher729 a quién le importa esto es TREMENDAMENTE útil :)
Charlie Parker

Respuestas:

108

Un efecto secundario se refiere simplemente a la modificación de algún tipo de estado, por ejemplo:

  • Cambiar el valor de una variable;
  • Escribir algunos datos en el disco;
  • Habilitar o deshabilitar un botón en la interfaz de usuario.

Al contrario de lo que algunas personas parecen estar diciendo:

  • Un efecto secundario no tiene que ser oculto o inesperado (puede serlo, pero eso no tiene nada que ver con la definición tal como se aplica a la informática);

  • Un efecto secundario no tiene nada que ver con la idempotencia. Una función idempotente puede tener efectos secundarios, y una función no idempotente puede no tener efectos secundarios (como obtener la fecha y hora actuales del sistema).

Es realmente muy simple. Efecto secundario = cambiar algo en alguna parte.

PD Como señala el comentarista benjol, varias personas pueden estar combinando la definición de un efecto secundario con la definición de una función pura , que es una función que es (a) idempotente y (b) no tiene efectos secundarios. Uno no implica el otro en ciencias de la computación en general, pero los lenguajes de programación funcionales suelen tender a imponer ambas restricciones.

Aaronaught
fuente
38
La frase "efecto secundario" hace que parezca que se está cambiando algo más de lo que se pretendía. En medicina, un medicamento tendrá el efecto principal de reducir el dolor y, a veces, un efecto secundario de causar hemorragias nasales, mareos, etc. El propósito del medicamento no es causar hemorragias nasales, pero a veces eso sucede como un Resultado extra no deseado .
FrustratedWithFormsDesigner
15
@ Frustrado: +1. Cada vez que veo ese término, no puedo evitar preguntarme si no fue elegido por los defensores de FP para crear precisamente esa connotación sutilmente siniestra.
Mason Wheeler
66
@Mason Wheeler. Existió mucho antes de FP. Y no es una connotación sutilmente siniestra. Es totalmente malvado y siempre lo ha sido. Durante las 3 décadas que he estado codificando, la declaración de "asignación criptográfica", el efecto secundario, ha preocupado a las personas. Una declaración de asignación simple y antigua es mucho más fácil de manejar.
S.Lott
77
@Mason Wheeler: En C. ++a. No parece una tarea. b = ++a;Tiene dos efectos secundarios. El obvio y la criptoasignación de a. Ese es el tipo de cosa que es un efecto secundario que (para algunos) es deseable. Pero se me ha llamado un efecto secundario para toda mi carrera para que no sea sutil.
S.Lott
55
@ Zachary, mira el último punto en mi respuesta. A lo que te refieres es a un comportamiento idempotente (o la falta del mismo). Eso no te dice nada sobre los efectos secundarios. Verificar el reloj del sistema no es un efecto secundario; de hecho, cualquier función o método con el prefijo "get" es uno que debe esperar razonablemente que no tenga ningún efecto secundario.
Aaronaught
36

Se dice que cualquier operación que modifica el estado de la computadora o que interactúa con el mundo exterior tiene un efecto secundario. Ver Wikipedia sobre efectos secundarios .

Por ejemplo, esta función no tiene efectos secundarios. Su resultado depende solo de sus argumentos de entrada, y nada sobre el estado del programa o su entorno cambia cuando se llama:

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

Por el contrario, llamar a estas funciones le dará diferentes resultados dependiendo del orden en que las llame, ya que cambian algo sobre el estado de la computadora:

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

Esta función tiene el efecto secundario de escribir datos en la salida. No llama a la función porque desea su valor de retorno; lo llamas porque quieres el efecto que tiene en el "mundo exterior":

int Write(const char* s) { return printf("Output: %s\n", s); }
Kristopher Johnson
fuente
1
Esta es una buena definición, pero no estoy loco por la elaboración, al igual que en la respuesta de Thorbjørn, parte de ella parece estar combinando el tema de los efectos secundarios con el de las funciones idempotentes; Como lo Writedemuestra su ejemplo, tener efectos secundarios no implica que la función cambie su salida con respecto a sus entradas, o incluso que su salida dependa de la entrada.
Aaronaught
66
No se trata de ser idempotente. El hecho de que produzca resultados significa que tiene un efecto secundario.
Kristopher Johnson
En algunos sistemas, la invocación square(x)puede provocar que el módulo donde se define la función se cargue desde el disco. ¿Debería considerarse esto un efecto secundario? Después de todo, esto indica que la (primera) llamada tarda inesperadamente, que el uso de RAM aumenta, etc.
Hagen von Eitzen
1
@HagenvonEitzen Cada operación en realidad realiza cambios en el estado de la computadora (registros de CPU, memoria, consumo de energía, calor, etc.). El "efecto secundario" generalmente se refiere a un entorno de ejecución idealizado imaginario donde nada sobre ese entorno cambia a menos que el programa lo cambie explícitamente. Pero si llama square(x) porque desea que cambie el estado de la computadora externa, puede considerar que se trata de un efecto secundario.
Kristopher Johnson
Para mí, la primera ilustración tiene mucho sentido. Sin embargo, el segundo menos. Creo que los efectos secundarios deben definirse en relación con un determinado entorno / alcance. Si considera todo el universo, no existe tal efecto secundario. Incluso si lo limita a la computadora, su función afectará a otros procesos ya que la CPU no se comportará igual. Si limita el alcance a cosas accesibles en un alcance de función local, entonces tenemos algo de qué hablar.
funct7
21

Creo que las respuestas existentes son bastante buenas. Me gustaría dar más detalles sobre algunos aspectos en los que la OMI no ha sido lo suficientemente estresada.

En matemáticas, una función es solo un mapeo de una tupla de valores a un valor. Entonces, dada una función fy un valor x, f(x)siempre será el mismo resultado y. Puede reemplazarlo f(x)con ytodas partes en una expresión y nada cambiará.

Lo que se llama una función (o procedimiento) en muchos lenguajes de programación es una construcción (código) que se puede ejecutar porque:

  1. Calcula una función en el sentido matemático, es decir, valores de entrada dados, devuelve un resultado o
  2. Produce algún efecto, por ejemplo, imprime algo en la pantalla, cambia un valor en una base de datos, lanza misiles, duerme durante 10 segundos, envía un SMS.

Por lo tanto, los efectos pueden estar relacionados con el estado pero también con otros aspectos como disparar un misil o pausar la ejecución durante unos segundos.

El término efecto secundario puede sonar negativo, pero normalmente el efecto de llamar a una función es el propósito mismo de la función misma. Supongo que, dado que el término función se usó originalmente en Matemáticas, calcular un valor se considera el efecto primario de una función, mientras que cualquier otro efecto se considera un efecto secundario . Algunos lenguajes de programación utilizan el término procedimiento para evitar confusiones con funciones en sentido matemático.

Tenga en cuenta que

  1. Algunos procedimientos son útiles tanto para su valor de retorno como para su efecto secundario.
  2. Algunos procedimientos solo calculan un valor de resultado y no tienen otros efectos. A menudo se les llama funciones puras porque todo lo que hacen es calcular una función en el sentido matemático.
  3. Algunos procedimientos, por ejemplo, sleep()en Python, solo son útiles por sus efectos (secundarios),. A menudo se modelan como funciones que devuelven un valor especial None, o unito ()o ..., lo que simplemente indica que el cálculo ha finalizado correctamente.
Giorgio
fuente
2
En mi humilde opinión, esta debería ser la respuesta aceptada. El concepto de un efecto secundario solo tiene sentido en términos de funciones matemáticas. Un procedimiento está diseñado para simplemente agrupar un conjunto de instrucciones de una manera estructurada mientras le permite saltar a ese conjunto desde cualquier lugar y regresar convenientemente. No hay efectos primarios previstos y secundarios. Tal vez podría decir que lanzar una excepción es un efecto secundario de un procedimiento, ya que rompe la intención del procedimiento que es regresarlo a donde lo dejó y continuar la ejecución desde allí.
Didier A.
4

Un efecto secundario es cuando una operación tiene un efecto en una variable / objeto que está fuera del uso previsto.

Puede suceder cuando realiza una llamada a una función compleja que tiene el efecto secundario de alterar alguna variable global, aunque esa no fue la razón por la que la llamó (tal vez la llamó para extraer algo de una base de datos).

Admito que estoy teniendo problemas para encontrar un ejemplo simple que no parezca totalmente artificial, y los ejemplos de cosas en las que he trabajado son muuuucho más largos para publicar aquí (y dado que está relacionado con el trabajo, probablemente no debería de todos modos )

Un ejemplo que he visto (hace un tiempo) era una función que abría una conexión de base de datos si la conexión estaba cerrada. El problema era que se suponía que debía cerrar la conexión al final de la función, pero el desarrollador olvidó agregar ese código. Entonces, aquí hubo un efecto secundario no deseado: se suponía que llamar a un procedimiento solo hacía una consulta y el efecto secundario era que la conexión permanecía abierta y si la función se llamaba dos veces seguidas, se generaría un error diciendo que la conexión era ya abierto


Ok, ya que todos están dando ejemplos ahora, creo que yo también lo haré;)

/*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 función do_task_xtiene un efecto primario de devolver el resultado de algunos cálculos, y un efecto secundario de posiblemente modificar una variable global.

Por supuesto, cuál es el principal y cuál es el efecto secundario podría estar abierto a interpretación y podría depender del uso real. Si llamo a esta función con el propósito de modificar el global y descarto el valor devuelto, diría que modificar el global es el efecto principal.

FrustratedWithFormsDesigner
fuente
2
No creo que esta sea una buena definición universal. Muchos programadores usan intencionalmente construcciones específicamente para sus efectos secundarios.
CB Bailey
@ Charles: Muy bien. En ese caso, ¿cómo lo definirías?
FrustratedWithFormsDesigner
2
Creo que @KristopherJohnson tiene la definición más clara. Cualquier cosa que altere ese estado del programa o su entorno o produzca un efecto en el mundo real, como generar resultados.
CB Bailey
@ Charles Bailey: Eso no cambia la definición. Usar cosas para el efecto secundario está bien. Siempre y cuando entiendas que hay un efecto secundario. No altera nada sobre esta definición.
S.Lott
1
@SLott: La definición en esta respuesta (es decir, el primer párrafo) incluye la cláusula: "fuera del uso previsto". Creo que mi comentario fue justo.
CB Bailey
3

En informática, se dice que una función o expresión tiene un efecto secundario si modifica algún estado o tiene una interacción observable con las funciones de llamada o el mundo exterior.

De Wikipedia - Efecto secundario

Una función, en el sentido matemático, es un mapeo de entrada a salida. El efecto deseado de llamar a una función es que asigne la entrada a la salida que devuelve. Si la función hace algo más, no importa qué, pero si tiene algún comportamiento que no esté asignando la entrada a la salida, se sabe que ese comportamiento es un efecto secundario.

En términos más generales, un efecto secundario es cualquier efecto que no sea el efecto previsto del diseñador de la construcción.

Un efecto es cualquier cosa que afecta a un actor. Si llamo a una función que envía a mi novia un mensaje de texto de ruptura, que afecta a un grupo de actores, a mí, a ella, a la red de la compañía de telefonía celular, etc. El único efecto previsto de llamar a una función libre de efectos secundarios es para la función para devolverme una asignación de mi entrada. Entonces para:

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

Si se pretende que sea una función, entonces lo único que debería hacer es devolver void. Si no tenía efectos secundarios, en realidad no debería enviar el mensaje de texto.

En la mayoría de los lenguajes de programación, no existe una construcción para una función matemática. Ninguna construcción está destinada a ser utilizada como tal. Es por eso que la mayoría de los idiomas dicen que tiene métodos o procedimientos. Por diseño, se pretende que puedan hacer muchos más efectos. En el lenguaje de programación común, a nadie realmente le importa la intención de lo que era un método o un procedimiento, por lo que cuando alguien dice que esta función tiene efectos secundarios, en realidad quieren decir que esta construcción no se comporta como una función matemática. Y cuando alguien dice que esta función no tiene efectos secundarios, quieren decir que esta construcción se comporta efectivamente como una función matemática.

Una función pura siempre está libre de efectos secundarios, por definición. Una función pura, es una forma de decir, esta función, aunque está utilizando una construcción que permite más efectos, solo tiene como efecto una igual a la de una función matemática.

Reto a cualquiera a que me diga cuándo una función libre de efectos secundarios no sería pura. A menos que el efecto primario deseado del contexto de la oración usando el término puro y sin efectos secundarios no sea el efecto matemático previsto de una función, entonces esos son siempre iguales.

Como tal, a veces, aunque más raramente, y creo que esta es la distinción que carece y también desorienta a las personas (ya que esa no es la suposición más común) en la respuesta aceptada, pero a veces se supone que el efecto deseado de una función de programación es para asignar entrada a salida, donde la entrada no está limitada a los parámetros explícitos de la función, pero la salida está limitada al valor de retorno explícito. Si supone que ese es el efecto deseado, entonces una función que lee un archivo y devuelve un resultado diferente en función de lo que está en el archivo aún no tiene efectos secundarios, ya que permitió que las entradas provengan de otros lugares en su efecto deseado.

Entonces, ¿por qué es todo esto importante?

Se trata de controlar y mantenerlo. Si llama a una función y hace otra cosa y luego devuelve un valor, es difícil razonar sobre su comportamiento. Tendrá que buscar dentro de la función el código real para adivinar lo que está haciendo y afirmar su corrección. La situación ideal es que es muy claro y fácil saber cuál es la entrada que está utilizando la función y que no está haciendo nada más que devolverle una salida. Puede relajar esto un poco y decir que saber exactamente qué entrada está utilizando no es tan útil como estar seguro de que no está haciendo nada más de lo que podría no estar enterado y luego devolver un valor, por lo que tal vez esté satisfecho con solo aplicar que no hace nada más que mapear la entrada, sin importar de dónde la obtenga, a la salida.

En casi todos los casos, el objetivo de un programa es tener otros efectos además de mapear las cosas que entran y las que salen. La idea de controlar el efecto secundario es que puede organizar el código de una manera que sea más fácil de entender y razonar. Si combina todos los efectos secundarios, en un lugar que es muy explícito y central, es fácil saber dónde mirar y confiar en que esto es todo lo que está sucediendo, nada más. Si la entrada también es muy explícita, ayuda a probar el comportamiento para diferentes entradas, y es más fácil de usar, ya que no necesita cambiar la entrada en muchos lugares diferentes, algunos que pueden no ser obvios, solo para conseguir lo que quieres

Debido a que lo más útil para comprender, razonar y controlar el comportamiento de un programa es tener todas las entradas claramente agrupadas y explícitas, así como tener todos los efectos secundarios agrupados y explícitos, esto es generalmente de lo que las personas hablan cuando dicen efecto secundario, puro, etc.

Debido a que lo más útil es la agrupación de los efectos secundarios y su carácter explícito, a veces las personas solo quieren decir eso, y lo distinguen diciendo que no es puro, sino que está libre de "efectos secundarios". Pero el efecto secundario es relativo al supuesto "efecto primario pretendido", por lo que es un término contextual. Esto me parece que se usa con menos frecuencia, aunque sorprendentemente se habla mucho en este hilo.

Finalmente, idempotente significa que llamar a esta función muchas veces con las mismas entradas (no importa de dónde provengan) siempre dará como resultado los mismos efectos (efecto secundario o no).

Didier A.
fuente
Creo que un gran problema para explicar los efectos secundarios es que hasta que haya usado un lenguaje como Ocaml o Haskell, puede ser muy difícil razonar sobre la programación libre de efectos secundarios (¡casi!).
Jamie Strauss
2

En la programación, un efecto secundario es cuando un procedimiento cambia una variable desde fuera de su alcance. Los efectos secundarios no dependen del idioma. Hay algunas clases de idiomas que tienen como objetivo eliminar los efectos secundarios (lenguajes funcionales puros), pero no estoy seguro de si hay alguno que requiera efectos secundarios, pero podría estar equivocado.

Hasta donde yo sé, no hay efectos secundarios internos y externos.

indyK1ng
fuente
Para ser más precisos, los lenguajes funcionales puros claramente separan el código libre de efectos secundarios de otro código, mientras que otros lenguajes no tienen ningún mecanismo para distinguir entre código puro e impuro. La mayoría de los programas deben tener efectos secundarios para ser de alguna utilidad.
Giorgio
Creo que algunos de los lenguajes de programación pre-gui como MS-BASIC y QBasic pueden haber estado tan cerca de un lenguaje de 'solo efectos secundarios' como puedas obtener. Y sí, puede tener efectos secundarios internos y externos.
James K
0

Aquí hay un ejemplo simple:

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

La definición de efecto secundario no es específica de la programación, así que simplemente imagine los efectos secundarios de sus medicamentos o de comer demasiada comida.

ChaosPandion
fuente
Pero si el mensaje entra como referencia y usted cambia el mensaje en su método, eso podría ser un efecto secundario. ¿Estoy en lo correcto?
Amir Rezaei
El hecho de que la expresión x++modifique la variable xse considera comúnmente como un efecto secundario. Ese valor de la expresión es el valor previo al incremento de x; Esta es la parte de efecto no secundario de la expresión.
CB Bailey
@Charles: estoy de acuerdo, aunque el ejemplo original no fue tan claro como el actual.
ChaosPandion
@Amir - Bueno, eso realmente depende del idioma. Si esto fuera C #, esto no se consideraría un efecto secundario.
ChaosPandion
@ChaosPandion: Personalmente, no estoy de acuerdo. El ejemplo original fue mucho más simple y claro.
CB Bailey
-2

Un efecto secundario son las cosas que suceden en el código que obviamente no son evidentes.

Por ejemplo, digamos que tienes esta clase

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

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

Cuando creas inicialmente la clase, le das una semilla.

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

No conoce las partes internas, solo espera obtener un valor aleatorio, y esperaría que randomGenerator. La semilla aún sea 15 ... pero no lo es.

La llamada a la función tuvo el efecto secundario de cambiar el valor de la semilla.

CaffGeek
fuente
10
Los efectos secundarios no tienen que estar ocultos. Estás pensando en el uso coloquial o médico; en programación, un efecto secundario simplemente se refiere a modificar algún estado.
Aaronaught
1
Imprimir en la consola es un efecto secundario. No esta oculto. De Wikipedia : "En informática, se dice que una función o expresión tiene un efecto secundario si, además de devolver un valor, también modifica algún estado o tiene una interacción observable con las funciones de llamada o el mundo exterior ".
Los efectos secundarios son cómo las no funciones (es decir, los procedimientos) realizan cualquier trabajo. X = 1; X = Y (10) son dos funciones puras. Cuando salga del reino "x = whatever", ya sea para escribir la salida en la pantalla | unidad | impresora | led o leer la entrada fuera del formato "x = y" o simplemente cambiar el valor de una variable de una cosa a otra Es un efecto secundario.
James K
Creo que por "oculto" quiere decir que no es obvio. Como en x = f (y, z) x se puede suponer que se basa en y y z. Mientras que proc (x, y, z) no le dice nada sobre lo que está sucediendo. Todo lo valioso podría ser cambiado, o ninguno. Proc podría ser un análogo a f, o completamente no relacionado. Una función pura tiene una sola respuesta: 'x'. Ir más allá de eso, es un efecto secundario. Totalmente previsto, pero los efectos secundarios.
James K
Al igual que para entender 0, primero debe comprender 1: para comprender los efectos secundarios, primero debe comprender las funciones.
James K