La evaluación de cortocircuito , evaluación mínima o evaluación de McCarthy (en honor a John McCarthy ) es la semántica de algunos operadores booleanos en algunos lenguajes de programación en los que el segundo argumento se ejecuta o evalúa solo si el primer argumento no es suficiente para determinar el valor de la expresión: cuando el primer argumento de la AND
función se evalúa como false
, el valor general debe ser false
; y cuando el primer argumento de la OR
función se evalúa como true
, el valor general debe ser true
.
En lenguajes de programación con evaluación diferida ( Lisp , Perl , Haskell ), los operadores booleanos habituales se cortocircuitan. En otros ( Ada , Java , Delphi ), están disponibles tanto operadores booleanos estándar como de cortocircuitación. Para algunas operaciones booleanas, como la operación exclusiva o (XOR), es imposible cortocircuitar, porque siempre se necesitan ambos operandos para determinar un resultado.
Los operadores de cortocircuito son, en efecto, estructuras de control en lugar de simples operadores aritméticos, ya que no son estrictos . En términos de lenguaje imperativo (en particular C y C++ ), donde los efectos secundarios son importantes, los operadores de cortocircuito introducen un punto de secuencia : evalúan completamente el primer argumento, incluidos los efectos secundarios , antes de procesar (opcionalmente) el segundo argumento. ALGOL 68 utilizó procedimientos para lograr operadores y procedimientos de cortocircuito definidos por el usuario .
El uso de operadores de cortocircuito ha sido criticado por ser problemático:
Los conectores condicionales —" cand " y " cor " para abreviar— son... menos inocentes de lo que podrían parecer a primera vista. Por ejemplo, cor no se distribuye sobre cand : compare
- (A cand B) cor C con (A cor C) cand (B cor C);
En el caso ¬A ∧ C , la segunda expresión requiere que B esté definido, la primera no. Como los conectores condicionales complican el razonamiento formal sobre los programas, es mejor evitarlos.
— Edsger W. Dijkstra [1]
En cualquier lenguaje de programación que implemente la evaluación por cortocircuito, la expresión es equivalente a la expresión condicional y la expresión es equivalente a . En cualquier caso, x solo se evalúa una vez.x and y
if x then y else x
x or y
if x then x else y
La definición generalizada anterior se adapta a los lenguajes de tipado flexible que tienen más de dos valores de verdad True
y False
, donde los operadores de cortocircuito pueden devolver la última subexpresión evaluada. Esto se denomina "último valor" en la tabla siguiente. Para un lenguaje de tipado estricto, la expresión se simplifica a y respectivamente para el caso booleano.if x then y else false
if x then true else y
Aunque AND
tiene prioridad en muchos lenguajes, no es una propiedad universal de la evaluación de OR
cortocircuito. Un ejemplo de los dos operadores que tienen la misma prioridad y son asociativos por la izquierda entre sí es la sintaxis de lista de comandos del shell POSIX . [2] : §2.9.3
El siguiente evaluador simple de izquierda a derecha impone una precedencia de AND
sobre OR
por a continue
:
función cortocircuito-eval( operadores , valores ) deja resultado := Verdadero para cada ( op , val ) en ( operadores , valores ): si op = "AND" && resultado = Falso continuar de lo contrario si op = "OR" && resultado = Verdadero devolver resultado de lo contrario resultado := val devolver resultado
La lógica de cortocircuito, con o sin efectos secundarios, se ha formalizado basándose en el condicional de Hoare . Un resultado es que los operadores que no generan cortocircuito se pueden definir a partir de la lógica de cortocircuito para que tengan la misma secuencia de evaluación. [3]
Al observar la siguiente tabla, tenga en cuenta que los operadores bit a bit a menudo no se comportan exactamente como operadores lógicos, incluso si ambos argumentos son de tipo 0
, 1
o booleano.
Ejemplos:
false
: (true & true) === (true && true)
, (false | false) === (false || false)
, (1 & 2) === (1 && 2)
.false
: (true & true) === (true && true)
, (0 | 0) === (0 || 0)
, (1 & 2) === (1 && 2)
.bool
o toman solo los valores 0
o 1
. [4]&&
y ||
están ansiosos y pueden devolver cualquier tipo.static if
y static assert
. Las expresiones en inicializadores estáticos o constantes de manifiesto utilizan una evaluación diligente.and:
sea un bloque (por ejemplo, false and: [Transcript show: 'Wont see me']
).AND
se OR
utiliza la evaluación de cortocircuito y no define los operadores AND_THEN
y OR_ELSE
. Las entradas de la tabla muestran cómo funciona para Beckhoff TwinCAT®.Ejemplo habitual, utilizando un lenguaje basado en C :
int denom = 0 ; if ( denom != 0 && num / denom ) { ... // garantiza que el cálculo de num/denom nunca dé como resultado un error de división por cero }
Consideremos el siguiente ejemplo:
int a = 0 ; si ( a != 0 && mifunción ( b )) { hacer_algo (); }
En este ejemplo, la evaluación de cortocircuito garantiza que myfunc(b)
nunca se llame a . Esto se debe a que a != 0
evalúa como falso . Esta característica permite dos construcciones de programación útiles.
Ambos se ilustran en el siguiente fragmento de código C, donde la evaluación mínima evita tanto la desreferencia de puntero nulo como la obtención de memoria en exceso:
bool is_first_char_valid_alpha_unsafe ( const char * p ) { return isalpha ( p [ 0 ]); // ERROR DE SEGMENTACIÓN es muy posible con p == NULL } bool is_first_char_valid_alpha ( const char * p ) { return p != NULL && isalpha ( p [ 0 ]); // 1) no hay ejecución innecesaria de isalpha() con p == NULL, 2) no hay riesgo de SEGFAULT }
Dado que la evaluación mínima es parte de la definición semántica de un operador y no una optimización opcional , varios modismos de codificación se basan en ella como una construcción condicional sucinta. Algunos ejemplos incluyen:
some_condition o die ; # Abortar la ejecución si some_condition es falsa some_condition y die ; # Abortar la ejecución si some_condition es verdadera
Modismos del shell POSIX : [13]
modprobe -q algún_módulo && echo "algún_módulo instalado" || echo "algún_módulo no instalado"
Este modismo presupone que echo
no puede fallar.
A pesar de estos beneficios, la evaluación mínima puede causar problemas a los programadores que no se dan cuenta (o se olvidan) de que está sucediendo. Por ejemplo, en el código
si ( expresiónA && mifunción ( b )) { hacer_algo (); }
Si myfunc(b)
se supone que debe realizar alguna operación requerida independientemente de si do_something()
se ejecuta, como asignar recursos del sistema, y expressionA
se evalúa como falso, entonces myfunc(b)
no se ejecutará, lo que podría causar problemas. Algunos lenguajes de programación, como Java , tienen dos operadores, uno que emplea una evaluación mínima y otro que no, para evitar este problema.
Los problemas con declaraciones de efectos secundarios no ejecutados se pueden resolver fácilmente con un estilo de programación adecuado, es decir, no utilizando efectos secundarios en declaraciones booleanas, ya que el uso de valores con efectos secundarios en las evaluaciones tiende a hacer que el código sea generalmente opaco y propenso a errores. [14]
Los cortocircuitos pueden provocar errores en la predicción de ramificaciones en las unidades centrales de procesamiento (CPU) modernas y reducir drásticamente el rendimiento. Un ejemplo notable es el código de intersección de caja alineada con el eje de un rayo altamente optimizado en el trazado de rayos . [ Aclaración necesaria ] Algunos compiladores pueden detectar estos casos y emitir código más rápido, pero la semántica del lenguaje de programación puede limitar estas optimizaciones. [ Cita requerida ]
Un ejemplo de un compilador incapaz de optimizar para tal caso es la máquina virtual (VM) Hotspot de Java a partir de 2012. [15]