Articulo de referencia

evaluación de cortocircuito

La evaluación de cortocircuito , evaluación mínima o evaluación McCarthy (en honor a John McCarthy ) es la semántica de algunos operadores booleanos en algunos lenguajes de prog...

La evaluación de cortocircuito , evaluación mínima o evaluación 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 ANDfunción se evalúa como false, el valor general debe ser false; y cuando el primer argumento de la ORfunción se evalúa como true, el valor general debe ser true.

En lenguajes de programación con evaluación perezosa ( Lisp , Perl , Haskell ), los operadores booleanos habituales se evalúan en cortocircuito. En otros ( Ada , Java , Delphi ), están disponibles tanto los operadores booleanos estándar como los de evaluación en cortocircuito. Para algunas operaciones booleanas, como la disyunción exclusiva (XOR), es imposible evaluar en cortocircuito, ya que se necesitan ambos operandos para determinar el resultado.

Los operadores de cortocircuito son, en efecto, estructuras de control más que simples operadores aritméticos, ya que no son estrictos . En términos de lenguajes imperativos (especialmente C y C++ ), donde los efectos secundarios son importantes, los operadores de cortocircuito introducen un punto de secuencia : evalúan completamente el primer argumento, incluyendo cualquier efecto secundario , antes de procesar (opcionalmente) el segundo argumento. ALGOL 68 utilizó `procduring` para lograr operadores y procedimientos de cortocircuito definidos por el usuario .

El uso de operadores de cortocircuito ha sido criticado por considerarse 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 : compárese

(A y B) cor C con (A cor C) y (B cor C);

En el caso ¬A ∧ C, la segunda expresión requiere que B esté definido, mientras que la primera no. Dado que los conectores condicionales complican el razonamiento formal sobre los programas, es mejor evitarlos.

Definición

En cualquier lenguaje de programación que implemente la evaluación de cortocircuito, la expresión es equivalente a la expresión condicional , y la expresión es equivalente a . En ambos casos, x se evalúa solo una vez.x and yif x then y else xx or yif x then x else y

La definición generalizada anterior se adapta a lenguajes de tipado flexible que tienen más de dos valores de verdadTrue 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 falseif x then true else y

Precedencia

Aunque ANDtiene precedenciaOR en muchos lenguajes, esta no es una propiedad universal de la evaluación de cortocircuito. Un ejemplo de los dos operadores que tienen la misma precedencia y son asociativos por la izquierda es la sintaxis de la lista de comandos del shell POSIX . [ 2 ] : §2.9.3

El siguiente evaluador simple de izquierda a derecha impone una precedencia de ANDsobre ORmediante un continue:

función short-circuit-eval ( operadores , valores ) sea resultado := Verdadero para cada ( op , val ) en ( operadores , valores ): si op = "AND" && resultado = Falso continuar sino si op = "OR" && resultado = Verdadero devolver resultado sino resultado := val devolver resultado

Formalización

La lógica de cortocircuito, con o sin efectos secundarios, se ha formalizado basándose en la condicional de Hoare . Como resultado, se pueden definir operadores sin cortocircuito a partir de la lógica de cortocircuito para que tengan la misma secuencia de evaluación. [ 3 ]

Comparación con operadores bit a bit

&Los operadores condicionales y lógicos |son operadores bit a bit que se encuentran en muchos lenguajes de programación. La principal diferencia radica en que los operadores bit a bit operan sobre los bits individuales de un número binario, mientras que los operadores condicionales operan sobre operaciones lógicas. Además, las expresiones a ambos lados de un operador bit a bit siempre se evalúan. En algunos lenguajes, como Java y C# , se pueden usar con operandos booleanos para forzar la evaluación de ambos lados.

si ( expresión1 || expresión2 || expresión3 )

Si la expresión 1 es verdadera, las expresiones 2 y 3 no se comprueban.

si ( expresión1 | expresión2 | expresión3 )

Esto comprueba las expresiones 2 y 3, incluso si la expresión 1 es verdadera.

Los operadores de cortocircuito pueden, por lo tanto, reducir los tiempos de ejecución al evitar cálculos innecesarios. También pueden evitar excepciones de valor nulo cuando la expresión 1 comprueba si un objeto es válido.

Compatibilidad con lenguajes comunes de programación, descripción de hardware y scripting.

La siguiente tabla se limita a los lenguajes de programación más comunes y a los operadores booleanos básicos para la conjunciónAND y disyunción lógicasOR . Los operadores bit a bit se muestran solo para los lenguajes que permiten su uso como operadores booleanos de ejecución inmediata y que tienen el mismo tipo de retorno.

Muchos lenguajes cuentan con otros operadores no estrictos , en particular expresiones condicionales con sintaxis variable, como la condicional ternaria . El operador Elvis es una sintaxis para un cortocircuito ANDque devuelve el último valor.

  1. Los operadores bit a bit se comportan como operadores booleanos cuando ambos argumentos son de tipoboolo toman solo los valores0o1. [ 4 ]
  2. Cuando se sobrecargan , los operadores&&y||son ansiosos y pueden devolver cualquier tipo.
  3. Esto solo se aplica a las expresiones evaluadas en tiempo de ejecución,static ifystatic assert. Las expresiones en los inicializadores estáticos o constantes manifiestas utilizan evaluación inmediata.
  4. En Fortran, las cláusulas pueden evaluarse en cualquier orden y opcionalmente se pueden cortocircuitar.
  5. 1 2 En Lua y OCaml, los operadores bit a bit&,|(OCamlland,lor) están restringidos a enteros y no se pueden usar con booleanos.
  6. En Java, estos, junto con otros,?…:a veces se denominan "operadores condicionales". [ 7 ]
  7. El operador&se comporta como un operador de cortocircuito cuando se usa en una instrucción después deiforwhile. [ 8 ]
  8. ISO/IEC 10206:1990 Extended Pascal permite, pero no exige, el cortocircuito.
  9. 1 2 Delphi y Free Pascal utilizan por defecto la evaluación en cortocircuito. Esto puede modificarse mediante opciones del compilador , pero no parece ser una práctica muy extendida.
  10. Smalltalk utiliza semántica de cortocircuito siempre que el argumentoand:sea un bloque (por ejemplo,).falseand: [Transcriptshow:'Wont see me']
  11. En VHDL, la evaluación de cortocircuito se define solo para los tipos escalares predefinidosbooleanybit, utilizando los operadores lógicosand,or,nand, ynor. Cuando estos operadores se aplican astd_logic(desdeieee.std_logic_1164), se sobrecargan como funciones y son de evaluación inmediata, por lo que ambos operandos siempre se evalúan.

Uso común

Evitar los efectos secundarios no deseados del segundo argumento

Ejemplo habitual, utilizando un lenguaje basado en C :

int denominador = 0 ; if ( denom != 0 && num / denominador ) { ... // garantiza que el cálculo de num/denom nunca produzca un error de división por cero }

Consideremos el siguiente ejemplo:

int a = 0 ; if ( a != 0 && myfunc ( b )) { hacerAlgo (); }

En este ejemplo, la evaluación de cortocircuito garantiza que myfunc(b)nunca se llame. Esto se debe a que se evalúa como falso . Esta característica permite dos construcciones de programación útiles.a != 0

  1. Si la primera subexpresión comprueba si se necesita un cálculo costoso y la comprobación resulta falsa , se puede eliminar el cálculo costoso en el segundo argumento.
  2. Permite una estructura en la que la primera expresión garantiza una condición sin la cual la segunda expresión puede causar un error en tiempo de ejecución .

Ambos casos se ilustran en el siguiente fragmento de código C, donde la evaluación mínima evita tanto la desreferenciación de punteros nulos como las búsquedas excesivas de memoria:

bool isFirstCharValidAlphaUnsafe ( const char * p ) { return isalpha ( p [ 0 ]); // Es muy probable que se produzca un error de segmentación con p == NULL }bool isFirstCharValidAlpha ( const char * p ) { return p != NULL && isalpha ( p [ 0 ]); // 1) no se ejecuta isalpha() innecesariamente con p == NULL, 2) no hay riesgo de SEGFAULT }

Construcción condicional idiomática

Dado que la evaluación mínima forma parte de la definición semántica de un operador y no es una optimización opcional , varios modismos de codificación se basan en ella como una construcción condicional concisa. Algunos ejemplos son:

Modismos de Perl :

alguna_condición o morir ; # Abortar la ejecución si alguna_condición es falsa alguna_condición y morir ; # Abortar la ejecución si alguna_condición es verdadera

Modismos de shell POSIX : [ 11 ]

modprobe -q some_module && echo "some_module instalado" || echo "some_module no instalado"

Este modismo presupone que echono puede fallar.

Posibles problemas

Una segunda condición no probada conduce a un efecto secundario no realizado.

A pesar de estos beneficios, una evaluación mínima puede causar problemas a los programadores que no se dan cuenta (o se olvidan) de que está ocurriendo. Por ejemplo, en el código

if ( expresiónA && myFunc ( b )) { hacerAlgo (); }

Si myFunc(b)se supone que debe realizar alguna operación requerida independientemente de si doSomething()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 las sentencias de efectos secundarios no ejecutadas se pueden resolver fácilmente con un estilo de programación adecuado, es decir, no utilizando efectos secundarios en sentencias booleanas, ya que el uso de valores con efectos secundarios en las evaluaciones tiende a hacer que el código sea opaco y propenso a errores. [ 12 ]

Eficiencia reducida debido a las limitaciones en las optimizaciones.

Los cortocircuitos pueden provocar errores en la predicción de bifurcaciones en las unidades centrales de procesamiento (CPU) modernas y reducir drásticamente el rendimiento; ejemplos notables incluyen intersecciones de rayos altamente optimizadas en el trazado de rayos . [ 13 ] Algunos compiladores pueden detectar estos casos y generar código más rápido, pero la semántica del lenguaje de programación puede limitar dichas optimizaciones.

Un ejemplo de un compilador incapaz de optimizar para tal caso es la máquina virtual (VM) Hotspot de Java a partir de 2012. [ 14 ]

Véase también

Referencias

  1. Edsger W. Dijkstra "Sobre una correspondencia algo decepcionante", EWD1009-0, 25 de mayo de 1987, texto completo
  2. "Lenguaje de comandos de shell" . pubs.opengroup.org .
  3. ^ Bergstra, enero A.; Ponse, A.; Staudt, DJC (2010). "Lógica de cortocircuito". arXiv : 1010.3674 [ cs.LO ].
  4. Norma ISO/IEC 9899, ​​secciones 6.2.5, 6.3.1.2, 6.5 y 7.16.
  5. Norma ISO/IEC 9899, ​​sección 6.5.13
  6. Borrador de la norma ISO/IEC IS 14882.
  7. "Operadores de igualdad, relacionales y condicionales (Tutoriales de Java™ > Aprendiendo el lenguaje Java > Conceptos básicos del lenguaje)" . docs.oracle.com . Consultado el 29 de abril de 2019 .
  8. "y, &" . Centro de ayuda de MathWorks . Consultado el 2 de febrero de 2025 .
  9. "operadores - Documentación para Ruby 3.3" . docs.ruby-lang.org . Consultado el 2 de abril de 2024 .
  10. "std::ops - Rust" . doc.rust-lang.org . Consultado el 12 de febrero de 2019 .
  11. "¿Qué significa || en bash?" . stackexchange.com . Consultado el 09-01-2019 .
  12. "Transparencia referencial, definición y capacidad de despliegue" (PDF) . Itu.dk. Consultado el 24 de agosto de 2013 .
  13. "CppCon 2019: Matt Godbolt "Trazado de rutas de tres maneras: Un estudio del estilo C++"" . 11 de octubre de 2019 vía YouTube.
  14. Wasserman, Louis (11 de julio de 2012). "Java: ¿En qué casos es mejor usar AND incondicional (& en lugar de &&)?" . Stack Overflow .