viernes, 17 de junio de 2011

Evaluación de expresiones lógicas booleanas en cortocircuito

Cuando un compilador o intérprete evalúa una expresión booleana, la mayoría de ellos lo hacen aplicando una optimización conocida como cortocircuito. Esta optimización, en la mayoría de los casos ahorra bastante trabajo en la evaluación de la expresión, pero si alguno de los términos implicados debe tener un efecto colateral, es muy posible que no lo obtengamos. No es elegante incluir términos con efectos colaterales en expresiones booleanas.
Antes de nada, vamos a conocer qué es la evaluación en cortocircuito.
Imagina que tenemos cuatro variables booleanas: a, b, c y d, y operamos con ellas de esta manera:











Es decir,  asignamos unos valores a a, b y c, y a d le asignamos la operación AND de las otras tres. Para que d tuviera un valor true, sería necesario que tanto a como b como c tuvieran un valor true.
Pues bien, cuando el compilador o el intérprete resuelven la cuarta línea y comprueban que a tiene un valor false no siguen comprobando b ni c, ya que si a es falso, d también lo será, sin necesidad de terminar de evaluar la expresión. Eso es una evaluación en cortocircuito.
Análogamente también se puede aplicar con la operación OR. Mira este ejemplo:

 








Cuando el compilador o el intérprete resuelven la cuarta línea, al comprobar que a es true no siguen comprobando b ni c, ya que el resultado será true independientemente de sus valores.
Esta optimización es muy sensata, y la aplican prácticamente todos los compiladores e intérpretes modernos. Sin embargo, tiene un cierto peligro.
En los ejemplos anteriores hemos utilizado variables booleanas en la expresión. Sin embargo, también podíamos haber utilizado funciones o métodos que devolvieran un booleano. Si esa función o método tuviera algún efecto colateral, no se puede garantizar su ejecución, ya que dependerá de si el compilador aplica el cortocircuito o no.
Observa este ejemplo, como de costumbre, en C#:
 
 Al hacer esta prueba con el compilador de C#, y tal y como esperábamos, sale un 1 por la consola. Se ha aplicado el cortocircuito. A la vista del código, cualquiera podría esperar un 2, y sin embargo no es así. Pero lo peor de todo no es eso... es que NO PODEMOS GARANTIZAR si se ejecutará prueba () o no. Quizá coja este código, lo meta en otro compilador que no aplique el cortocircuito y resulta que si se ejecuta prueba ().
La cuestión no tendría importancia si en el contexto de mi programa, la ejecución o no del método prueba () en ese momento no influyera en ningún otro aspecto. Pero en este caso, el método prueba () tiene un EFECTO COLATERAL: cambia el valor de una variable.
Obviamente, y como programadores elegantes, no podemos dejar que ese efecto se produzca unas veces sí y otras no, según el compilador aplique la optimización o no.
Así pues, si un método tiene efectos colaterales, no estará involucrado en expresiones booleanas.
Una forma más elegante de lograr lo mismo es esta:


No hay comentarios:

Publicar un comentario