<commit_before>Definiciones
------------

Operación:aplicar una función, evaluar un predicado, enviar un mensaje, etc.
Transparencia Referencial  
Hay transparencia referencial si al reemplazar una operación por su resultado se logra el mismo efecto.

Una definición alternativa dice: Hay transparencia referencial cuando al realizar una operación con los mismos valores siempre da el mismo resultado. Si bien esta parece más fácil de entender, no es tan precisa como la primera; puede ser útil para dar los primeros pasos, pero para el final hay que terminar de entender la otra.

<!-- -->

  
También se puede pensar en las propiedades necesarias para tener Transparencia Referencial.

Decimos que una operación tiene transparencia referencial si es:

-   Independiente: No dependen del estado de nada que este fuera de si misma
-   Sin estado/Stateless: No tiene un estado que se mantenga de llamada en llamada
-   Determinística: Siempre devuelven el mismo valor dados los mismos argumentos

Efecto de Lado/Colateral (Side Effect)  
Hay efecto de lado cuando un cambio de estado sobrevive a la realización de una operación. Por ejemplo, una operación puede modificar una variable global, modificar uno de sus argumentos, escribir datos a la pantalla o a un archivo, o hacer uso de otras operaciones que tienen efecto de lado.

Otra definición válida es:

  
Si le sacás una foto al sistema (llamémosla F1), después realizas la operación de tu interés, y le volvés a sacar una foto al sistema (F2). Si F1 y F2 son distintas =&gt; la operación que hiciste tiene efecto de lado.

<!-- -->

Asignación Destructiva  
Asignar destructivamente es reemplazar el valor de una variable por otro valor.

**Nota1:** La [unificación](unificacion-y-pattern-matching.html) no se considera asignación (al momento de ligar no había ningún valor anterior, ¿sería más bien una inicialización?)

**Nota2:** Unificar es encontrar una sustitución capaz de igualar 2 términos

**Nota3:** Cuando se efectiviza está sustitución hablamos de ligado de variables (tal valor se ligó a tal variable)

¿Por qué nos interesa pensar en estos conceptos?
------------------------------------------------

Estos son algunos ejemplos concretos sobre cómo la existencia o no de efecto, asignación destructiva y transparencia referencial afectan a la hora de programar.

**Separar la lógica que hace cosas de la que consulta:** Muy seguido vemos métodos (o procedimientos, dependiendo del paradigma) que tienen efecto y a su vez retornan algún valor relacionado con el mismo, estas prácticas pueden llevar a confusiones que producen un funcionamiento erróneo del sistema, sobre todo cuando el nombre del método elegido no denota que existe un efecto asociado a su ejecución. Es una buena práctica tener separada la lógica que realiza modificaciones sobre el sistema de los que sólo pretenden obtener el resultado de una consulta, que nuestros métodos tengan un único objetivo, lo cual simplifica su uso y la elección de un nombre suficientemente representativo.

**Optimizaciones:** Tener asegurada la transparencia referencial permite hacer optimizaciones como las que tiene el motor de Haskell que afectan globalmente a los programas construidos con el mismo. La [evaluación perezosa o lazy](estrategias-de-evaluacion-lazy-evaluation.html) es posible gracias a esta característica.

**[Testing](testing.html):** El testeo unitario se basa en la premisa de que cada test sea independiente del otro y eso se logra controlando que el estado del sistema antes y después de correr cada test sea el mismo, por ese motivo es importante mantener el efecto controlado y poder revertir aquellos cambios que sobrevivan a la ejecución de cada test particular. También la transparencia referencial es importante para el testeo unitario ya que testear el resultado de una operación que depende de algo no determinístico no es viable y hace falta usar estrategias de testeo más avanzadas ([Mock Objects](http://es.wikipedia.org/wiki/Objeto_simulado)) para evitar este tipo de dependencia.

Ejemplos
--------

Cuando hablamos de que "algo" tiene transparencia referencial, efecto de lado o asignación destructiva, ese "algo" es la realización de una operación, de un lenguaje en particular o de un paradigma.

Estos tres conceptos suelen ir de la mano y si bien pueden darse relaciones entre ellas es saludable poder detectar la aparición de cada uno de ellos individualmente. Una relación que surge de la definición de transparencia referencial es que para ésta se dé, no puede haber efecto colateral, ya que si el estado del sistema se modifica, no es lo mismo ejecutar esa operación que reemplazar por el resultado.

A continuación mostramos algunos ejemplos en Smalltalk, ya que permite la aparición de todas estas características, para dejar más en claro de qué manera podemos identificarlas.

### Ejemplo 1

`Date today`

-   Transparencia Referencial: NO (Con cualquiera de las 2 definiciones de transparencia referencial)
-   Efecto de Lado: NO
-   Asignación Destructiva: NO

Evaluarlo con los mismos parámetros (o sea ninguno) en días distintos va a dar resultados distintos. Reemplazar la operación por el resultado una vez que cambia el día se rompe todo. Asignación destructiva y efecto de lado hay, pero en la CPU que actualiza la variable que indica el tiempo, no en el mensaje `today` que consulta ese valor (no se si es tan así, pero es a modo ilustrativo).

El efecto colateral de otra operación afecta a esta operación y le hace perder la transparencia referencial, a pesar de que esta operación por si misma NO tiene efecto de lado.

Ejemplos como este hacen que transparencia referencial y efecto colateral no sean conceptos opuestos.

### Ejemplo 2

`#LaColeccionConEfectoDeLado`
`>>add: unElemento`
`  "El add: siempre devuelve lo que se agrega. Acá se redefine para avisarle `
`   al elemento que fue agregado (no se me ocurrió nada mejor)"`
`  unElemento teAgregaronEn: self.`
`  ^super add: unElemento.`

-   Transparencia Referencial: NO (si te toma la definición alternativa SI, por eso dicha definición no es correcta). En un final, si se da un caso como este y están en duda, justifiquen por qué sí o no.
-   Efecto colateral: SI, porque la colección, luego de recibir el mensaje add: se modifica.
-   Asignación destructiva: no se la ve directamente en éste método, si bien puede estar presente en `teAgregaronEn:` o en `add:`. Probablemente no tenga mucho sentido hablar de asignación destructiva en este ejemplo.

Asumiendo que los parámetros siempre entienden el mensaje `#teAgregaronEn:` no importa cuantas veces se realicen estás operaciones siempre devuelven el parámetro.

`LaColeccionConEfectoDeLado new add: 4. "Devuelve 4"`
`LaColeccionConEfectoDeLado new add: pepita. "Devuelve pepita"`

Pero obviamente no es lo mismo escribir

`(LaColeccionConEfectoDeLado new add: 4) que esto (4)`

Acá se puede ver la importancia de utilizar la definición correcta de transparencia referencial.

### Ejemplo 3

`#Number`
` >>factorial`
`    | resultado |`
`    resultado := 1.`
`    self < 0 ifTrue: [ self error: 'Como que no va pedirle el factorial a un número negativo' ].`
`    1 to: self do: [ :indice | resultado := resultado * indice ].`
`    ^resultado`

-   Transparencia Referencial: SI (con las 2 definiciones)
-   Efecto colateral: NO
-   Asignaciones Destructivas: SI

### El efecto colateral dependiendo del contexto

`#Collection`
`select: aBlock`
`   | newCollection |`
`   newCollection := self species new.`
`   self do: [:each | (aBlock value: each) ifTrue: [newCollection add: each]].`
`   ^newCollection`

Sabemos que el método `select:` no tiene efecto colateral en sí mismo, porque no modifica la colección original (`self`), sino que devuelve una nueva de su mismo tipo.

Sin embargo podemos ver dentro de `select:` efectos colaterales en la asignación de `newCollection` y en el `add:`. Ambos pueden ser considerados como efectos colaterales dentro de la ejecución del método, pero quien usa `select:` no se da cuenta de eso y para él no tiene efecto de lado. Es decir, las asignaciones destructivas de variables locales *no presuponen* un efecto colateral para el sistema visto como un todo, ya que esos cambios de estado no perduran más allá de la ejecución del método. Sí podría analizarse como efecto *colateral* dentro del método. Probablemente en un método tan pequeño como este no tenga importancia ese tipo de análisis, pero en el caso de algoritmos más complejos podría cobrar valor (y asumiendo que no sea posible partir un algoritmo complejo en operaciones más pequeñas que simplifiquen justamente el análisis, pero eso ya es otra cuestión).

Por otra parte, aunque el `select:` no genera efectos de lado, no nos garantiza que el bloque que viene como parámetro no pueda tenerlo, por lo que uno debe tener cuidado con eso.

Preguntas frecuentes
--------------------

Leí una definición de Transparencia Referencial: “Hay transparencia referencial si al reemplazar una operación por su resultado se logra el mismo efecto”

Con este criterio, aquí sí habría transparencia referencial:

`int a=1;`
`int c;`
`c=a++;`

Ya que es lo mismo que hacer esto:

`int a=1;`
`int c;`
`c=1;`

Ya que el efecto en la variable c es el mismo: va a valer 1.<commit_msg>Revision without comments imported from MediaWiki<commit_after>Definiciones
------------

Operación:aplicar una función, evaluar un predicado, enviar un mensaje, etc.
Transparencia Referencial  
Hay transparencia referencial si al reemplazar una operación por su resultado se logra el mismo efecto.

Una definición alternativa dice: Hay transparencia referencial cuando al realizar una operación con los mismos valores siempre da el mismo resultado. Si bien esta parece más fácil de entender, no es tan precisa como la primera; puede ser útil para dar los primeros pasos, pero para el final hay que terminar de entender la otra.

<!-- -->

  
También se puede pensar en las propiedades necesarias para tener Transparencia Referencial.

Decimos que una operación tiene transparencia referencial si es:

-   Independiente: No dependen del estado de nada que este fuera de si misma
-   Sin estado/Stateless: No tiene un estado que se mantenga de llamada en llamada
-   Determinística: Siempre devuelven el mismo valor dados los mismos argumentos

Efecto de Lado/Colateral (Side Effect)  
Hay efecto de lado cuando un cambio de estado sobrevive a la realización de una operación. Por ejemplo, una operación puede modificar una variable global, modificar uno de sus argumentos, escribir datos a la pantalla o a un archivo, o hacer uso de otras operaciones que tienen efecto de lado.

Otra definición válida es:

  
Si le sacás una foto al sistema (llamémosla F1), después realizas la operación de tu interés, y le volvés a sacar una foto al sistema (F2). Si F1 y F2 son distintas =&gt; la operación que hiciste tiene efecto de lado.

<!-- -->

Asignación Destructiva  
Asignar destructivamente es reemplazar el valor de una variable por otro valor.

**Nota1:** La [unificación](unificacion-y-pattern-matching.html) no se considera asignación (al momento de ligar no había ningún valor anterior, ¿sería más bien una inicialización?)

**Nota2:** Unificar es encontrar una sustitución capaz de igualar 2 términos

**Nota3:** Cuando se efectiviza está sustitución hablamos de ligado de variables (tal valor se ligó a tal variable)

Ejemplos
--------

Cuando hablamos de que "algo" tiene transparencia referencial, efecto de lado o asignación destructiva, ese "algo" es la realización de una operación, de un lenguaje en particular o de un paradigma.

Estos tres conceptos suelen ir de la mano y si bien pueden darse relaciones entre ellas es saludable poder detectar la aparición de cada uno de ellos individualmente. Una relación que surge de la definición de transparencia referencial es que para ésta se dé, no puede haber efecto colateral, ya que si el estado del sistema se modifica, no es lo mismo ejecutar esa operación que reemplazar por el resultado.

A continuación mostramos algunos ejemplos en Smalltalk, ya que permite la aparición de todas estas características, para dejar más en claro de qué manera podemos identificarlas.

### Ejemplo 1: consulta no determinística

`Date today`

-   Transparencia Referencial: NO (Con cualquiera de las 2 definiciones de transparencia referencial)
-   Efecto de Lado: NO
-   Asignación Destructiva: NO

Evaluarlo con los mismos parámetros (o sea ninguno) en días distintos va a dar resultados distintos. Reemplazar la operación por el resultado una vez que cambia el día se rompe todo. Asignación destructiva y efecto de lado hay, pero en la CPU que actualiza la variable que indica el tiempo, no en el mensaje `today` que consulta ese valor (no se si es tan así, pero es a modo ilustrativo).

El efecto colateral de otra operación afecta a esta operación y le hace perder la transparencia referencial, a pesar de que esta operación por si misma NO tiene efecto de lado.

Ejemplos como este hacen que transparencia referencial y efecto colateral no sean conceptos opuestos.

### Ejemplo 2: método con efecto

`#LaColeccionConEfectoDeLado`
`>>add: unElemento`
`  "El add: siempre devuelve lo que se agrega. Acá se redefine para avisarle `
`   al elemento que fue agregado (no se me ocurrió nada mejor)"`
`  unElemento teAgregaronEn: self.`
`  ^super add: unElemento.`

-   Transparencia Referencial: NO (si te toma la definición alternativa SI, por eso dicha definición no es correcta). En un final, si se da un caso como este y están en duda, justifiquen por qué sí o no.
-   Efecto colateral: SI, porque la colección, luego de recibir el mensaje add: se modifica.
-   Asignación destructiva: no se la ve directamente en éste método, si bien puede estar presente en `teAgregaronEn:` o en `add:`. Probablemente no tenga mucho sentido hablar de asignación destructiva en este ejemplo.

Asumiendo que los parámetros siempre entienden el mensaje `#teAgregaronEn:` no importa cuantas veces se realicen estás operaciones siempre devuelven el parámetro.

`LaColeccionConEfectoDeLado new add: 4. "Devuelve 4"`
`LaColeccionConEfectoDeLado new add: pepita. "Devuelve pepita"`

Pero obviamente no es lo mismo escribir

`(LaColeccionConEfectoDeLado new add: 4) que esto (4)`

Acá se puede ver la importancia de utilizar la definición correcta de transparencia referencial.

### Ejemplo 3: método de consulta determinística

`#Number`
` >>factorial`
`    | resultado |`
`    resultado := 1.`
`    self < 0 ifTrue: [ self error: 'Como que no va pedirle el factorial a un número negativo' ].`
`    1 to: self do: [ :indice | resultado := resultado * indice ].`
`    ^resultado`

-   Transparencia Referencial: SI (con las 2 definiciones)
-   Efecto colateral: NO
-   Asignaciones Destructivas: SI

### Ejemplo 4: El efecto colateral dependiendo del contexto

`#Collection`
`select: aBlock`
`   | newCollection |`
`   newCollection := self species new.`
`   self do: [:each | (aBlock value: each) ifTrue: [newCollection add: each]].`
`   ^newCollection`

Sabemos que el método `select:` no tiene efecto colateral en sí mismo, porque no modifica la colección original (`self`), sino que devuelve una nueva de su mismo tipo.

Sin embargo podemos ver dentro de `select:` efectos colaterales en la asignación de `newCollection` y en el `add:`. Ambos pueden ser considerados como efectos colaterales dentro de la ejecución del método, pero quien usa `select:` no se da cuenta de eso y para él no tiene efecto de lado. Es decir, las asignaciones destructivas de variables locales *no presuponen* un efecto colateral para el sistema visto como un todo, ya que esos cambios de estado no perduran más allá de la ejecución del método. Sí podría analizarse como efecto *colateral* dentro del método. Probablemente en un método tan pequeño como este no tenga importancia ese tipo de análisis, pero en el caso de algoritmos más complejos podría cobrar valor (y asumiendo que no sea posible partir un algoritmo complejo en operaciones más pequeñas que simplifiquen justamente el análisis, pero eso ya es otra cuestión).

Por otra parte, aunque el `select:` no genera efectos de lado, no nos garantiza que el bloque que viene como parámetro no pueda tenerlo, por lo que uno debe tener cuidado con eso.

¿Por qué nos interesa pensar en estos conceptos?
------------------------------------------------

Estos son algunos ejemplos concretos sobre cómo la existencia o no de efecto, asignación destructiva y transparencia referencial afectan a la hora de programar.

**Separar la lógica que hace cosas de la que consulta:** Muy seguido vemos métodos (o procedimientos, dependiendo del paradigma) que tienen efecto y a su vez retornan algún valor relacionado con el mismo, estas prácticas pueden llevar a confusiones que producen un funcionamiento erróneo del sistema, sobre todo cuando el nombre del método elegido no denota que existe un efecto asociado a su ejecución. Es una buena práctica tener separada la lógica que realiza modificaciones sobre el sistema de los que sólo pretenden obtener el resultado de una consulta, que nuestros métodos tengan un único objetivo, lo cual simplifica su uso y la elección de un nombre suficientemente representativo.

**Optimizaciones:** Tener asegurada la transparencia referencial permite hacer optimizaciones como las que tiene el motor de Haskell que afectan globalmente a los programas construidos con el mismo. La [evaluación perezosa o lazy](estrategias-de-evaluacion-lazy-evaluation.html) es posible gracias a esta característica.

**[Testing](testing.html):** El testeo unitario se basa en la premisa de que cada test sea independiente del otro y eso se logra controlando que el estado del sistema antes y después de correr cada test sea el mismo, por ese motivo es importante mantener el efecto controlado y poder revertir aquellos cambios que sobrevivan a la ejecución de cada test particular. También la transparencia referencial es importante para el testeo unitario ya que testear el resultado de una operación que depende de algo no determinístico no es viable y hace falta usar estrategias de testeo más avanzadas ([Mock Objects](http://es.wikipedia.org/wiki/Objeto_simulado)) para evitar este tipo de dependencia.

Preguntas frecuentes
--------------------

Leí una definición de Transparencia Referencial: “Hay transparencia referencial si al reemplazar una operación por su resultado se logra el mismo efecto”

Con este criterio, aquí sí habría transparencia referencial:

`int a=1;`
`int c;`
`c=a++;`

Ya que es lo mismo que hacer esto:

`int a=1;`
`int c;`
`c=1;`

Ya que el efecto en la variable c es el mismo: va a valer 1.
{'fraction_non_alphanumeric': 0.05669578264830395, 'fraction_numerical': 0.002625797116981941, 'mean_word_length': 4.3998842592592595, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '833945', 'n_tokens_mistral': 5955, 'n_tokens_neox': 5861, 'n_words': 2762}