Evaluación de cortocircuito
La evaluación de corto-circuito,[1] evaluación mínima, o evaluación McCarthy (por el científico John McCarthy) denota la semántica de algunos operadores booleanos en algunos lenguajes de programación en los cuales el segundo argumento no se ejecuta o evalúa si el primer argumento de la función AND
evalúa y el resultado es falso, el valor total tiene que ser falso; y cuando el primer argumento de la función OR
evalúa y el resultado es verdadero, el valor total tiene que ser verdadero. En algunos lenguajes de programación, como Lisp, los operadores booleanos usuales son corto-circuito. En otros (Java, Ada), tanto los corto-circuito y los operadores booleanos están disponibles. Para algunos operadores booleanos, como XOR
, no le es posible evaluar por corto-circuito, porque ambos operadores están obligados a determinar el resultado.
La expresión de corto-circuito x Sand y
(usando Sand
para denotar la variedad de corto-circuito) es equivalente a la sentencia condicional if x then y else false
; la expresión x Sor y
es equivalente a if x then true else y
.
Los operadores corto-circuito son estructuras de control en vez de simples operadores aritméticos, al igual que no son strict. ALGOL 68 usó "Proceduring" para lograr operadores y procedimientos de corto-circuito definidos por los usuarios.
En lenguajes aproximados o imprecisos, los cuales tienen más de dos valores de verdad Verdadero
y Falso
, los operadores corto-circuito podrían devolver la última subexpresión evaluada, de esta manera x Sor y
y x Sand y
son equivalentes a if x then x else y
y if x then y else x
respectivamente (sin evaluar x
dos veces). Esto es llamado "el último valor" en la tabla de abajo.
En lenguajes que emplean una evaluación perezosa por defecto, como Haskell, todas las funciones son efectivamente de "corto-circuito", y no son necesarios operadores especiales de corto-circuito.
Soporte en lenguajes comunes de programación
[editar]Lenguaje | Operadores ansiosos | Operadores de corto-circuito | Tipo de resultado |
---|---|---|---|
ABAP | none | and , or
|
Boolean1 |
Ada, Eiffel | and , or
|
and then , or else
|
Boolean |
ALGOL 68 | and, &, ∧; or, ∨ | andf , orf | Boolean |
C2 | none | && , || , ? [2]
|
Numeric (&& ,|| ), opnd-dependent (? )
|
C++3 | & , |
|
&& , || , ? [3]
|
Boolean (&& ,|| ), opnd-dependent (? )
|
Go, OCaml, Haskell | none | && , ||
|
Boolean |
C#, Java, | & , |
|
&& , ||
|
Boolean |
ColdFusion | none | AND , OR , && , ||
|
Boolean |
Erlang | and , or
|
andalso , orelse
|
Boolean |
Fortran | .and. , .or.
|
Boolean | |
JavaScript | none | && , ||
|
Last value |
Lisp, Lua, Scheme | none | and , or
|
Last value |
Modula-2 | none | AND , OR
|
Boolean |
Oberon | none | & , OR
|
Boolean |
Pascal | and , or 4
|
and_then , or_else 5
|
Boolean |
Perl, Ruby | & , |
|
&& , and , || , or
|
Last value |
PHP | none | && , and , || , or
|
Boolean |
Python | none | and , or
|
Last value |
Smalltalk | & , |
|
and: , or:
|
Boolean |
Standard ML | andalso , orelse
|
Boolean | |
Visual Basic .NET | And , Or
|
AndAlso , OrElse
|
Boolean |
VB Script, VB Classic, VBA | And , Or
|
Select Case
|
Numeric |
1ABAP en realidad no posee una distinción de los tipos de booleanos.
2 C, antes de C99, en realidad no tenía una distinción de los tipos de booleanos; los operadores lógicos devuelven 0 (para Falso) o 1 (para Verdadero).
3 Cuando es sobrecargado, los operadores && y || son ansiosos y pueden devolver cualquier tipo.
4 ISO Pascal permite pero no requiere corto-circuito.
5 ISO-10206 extendió a Pascal el soporte a and_then
and or_else
.[4]
Uso común
[editar]Evitando los efectos colaterales de ejecución en las expresiones secundarias
[editar]Ejemplo común.
int denom = 0;
if (denom && num/denom) {
... // asegura que no se produzca un error al calcular num/denom es decir una división por cero
}
Considere el siguiente ejemplo usando lenguaje Lenguaje C:
int a = 0;
if (a && myfunc(b)) {
do_something();
}
En este ejemplo, la evaluación de corto-circuito garantiza que myfunc(b)
nunca será llamado. Esto se debe a que la evaluación de a
es falso. Esta característica permite la programación de dos constructores. Inicialmente si se revisa la primera subexpresión, sin importar si es necesario un costo computacional y el proceso evaluado es falso, uno puede eliminar el costo computacional en el segundo argumento. Luego permite una construcción donde la primera expresión garantiza una condición sin la cual la segunda expresión pueda causar un error de ejecución run-time error. Ambos están ilustrados en el siguiente fragmento de código C donde una evaluación mínima previene una desferenciación a un apuntador a null y un desbordamiento de memoria.
bool is_first_char_valid_alpha_unsafe(const char *p)
{
return isalpha(p[0]); // Fallo de Segmentación altamente posible con p==NULL
}
bool is_first_char_valid_alpha(const char *p)
{
return p != NULL && isalpha(p[0]); // a) es innecesario la ejecución de isalpha() cuando p == NULL, b) No hay riesgo de Fallo de Segmentación
}
Posibles problemas
[editar]Segunda condición sin verificar dirige a un efecto colateral no ejecutado
[editar]A pesar de estos beneficios una evaluación mínima puede causar problema para los programadores que no se den cuenta (o se olviden) que está pasando. Por ejemplo, en el código
if (expressionA && myfunc(b)) {
do_something();
}
Si myfunc(b)
pretende realizar alguna operación requerida sin tener en cuenta si do_something()
es ejecutado, tal como la asignación de recursos al sistema, y expressionA
es evaluado como Falso, entonces myfunc(b)
no se ejecutará lo cual puede causar problemas. Algunos lenguajes de programación tales como Java, tienen dos operadores, uno que emplea la evaluación mínima y el otro que no, para evitar este problema
Problemas con las declaraciones incumplidas de efectos secundarios pueden ser resueltos fácilmente con el estilo de programación adecuada, es decir, no usando efectos colaterales en las declaraciones booleanas, así como usando valores con efectos colaterales en las evaluaciones tiende generalmente a producir un código opaco y propenso a errores.[5]
Desde que las evaluaciones mínimas son parte de las definiciones de las operaciones semánticas y no (opcional) de una optimización, muchos estilos de codificación se basan en él como un constructor condicional conciso, tal como el lenguaje Perl:
some_condition or die; # Cancelar la ejecución si some_condition es falso
some_condition and die; # Cancelar la ejecución si some_condition es verdadero
Eficiencia de la codificación
[editar]Si ambas expresiones usadas como condiciones son simples variables booleanas, puede ser mucho más rápido de evaluar las dos condiciones usadas en las operaciones booleanes de una vez, como si requiriera un simple ciclo de cálculo, en contraposición a uno o dos ciclos usados en las evaluaciones de los circuitos cortos (dependiendo del valor del primero). La diferencia en términos de eficiencia computacional entre estos dos casos depende fuertemente del compilador y del esquema de optimización utilizado; con la correcta optimización estos serán capaces de ejecutarse a la misma velocidad, así como serán compilados a un código máquina idéntico.[6]
Un corto-circuito puede llevar a errores en predictor de saltos en los modernos unidaded centrales de procesamiento, y reducir dramáticamente el desempeño (un ejemplo claro es un rayo altamente optimizado con el eje de la caja del código de intersección alineado en el trazado de rayos alineado trazado de rayos). Algunas compilaciones pueden detectar tales casos y emitir una codificación más rápida, pero no siempre es posible debido a violaciones de segmento del lenguaje C. Un código altamente optimizado debería emplear otras formas de hacer esto (como el manual de uso del código de máquina).
Referencias
[editar]- ↑ «Evaluación booleana por corto-circuito». Unecentro. Consultado el 28 de febrero de 2022.
- ↑ ISO/IEC 9899 standard.
- ↑ ISO/IEC IS 14882 draft.
- ↑ Pascal reference
- ↑ [1]
- ↑ [2]