Motivo de la existencia de operadores lógicos que no sean de cortocircuito

Cuando se usa con operandos boolean , & y | convertirse en operadores lógicos según la Sección 15.22.2 de JLS . A diferencia de && y || Sin embargo, estos no producen cortocircuitos. ellos siempre evalúan ambos lados. Tengo una pregunta tonta: ¿por qué los operadores lógicos que no son de cortocircuito menos eficientes ( & , | ) siguen ahí, cuando tenemos los operadores lógicos de cortocircuito más eficientes ( && , || )? Quiero decir, ¿cuál es el uso real de los operadores lógicos que no son de cortocircuito, a diferencia de los operadores lógicos de cortocircuito? En otras palabras, ¿cuál es el uso de evaluar siempre ambos lados mediante el uso de operadores lógicos que no sean de cortocircuito?

Respuesta actualizada :

Disculpas, me perdí la palabra “lógico” en tu pregunta a pesar de que está allí. (Me he tomado la libertad de enfatizarlo un poco con una edición).

Considere el caso en el que desea que siempre se produzcan efectos colaterales, independientemente de si la expresión de la izquierda evalúa true o false . Por ejemplo, contraste

 if (foo() & bar()) { // Only call this if both operations returned true } 

con

 if (foo() && bar()) { // Only call this if both operations returned true } 

Supongamos que tanto foo como bar tienen efectos que queremos que suceda, independientemente de si foo devuelve true o false . En la primera de arriba, que la bar siempre será llamada y tendrá su efecto. En este último, por supuesto, bar puede o no ser llamado. Si no tuviéramos la versión sin cortocircuito, tendríamos que usar variables temporales:

 boolean fooResult, barResult; fooResult = foo(); barResult = bar(); if (fooResult && barResult) { // ... } 

Podrías discutir (probablemente) que deberías hacer eso de todos modos , porque es demasiado fácil malinterpretar if (foo() & bar()) , pero ahí vamos, una razón pragmática para tener versiones que no sean de corto circuito.

Respuesta original :

¿Cómo propondrías & (o | ) ser un operador en cortocircuito? Con && y || , tiene sentido porque se trata de condiciones booleanas: pueden ser verdaderas o falsas, no hay tonos de gris. Pero & y | tratar con bits, no booleanos. El resultado es un número. Quiero decir, supongo que no pude evaluar el lado derecho si el lado izquierdo fuera 0 , y lo mismo | no podría evaluarlo si el lado izquierdo fuera todo-bits-encendido para lo que sea que sea el tipo, pero no veo mucho sentido hacer significativo el caso de un borde de cada operador (en comparación con los otros 254 casos) )

Hay instancias en las que los componentes de una expresión booleana implican operaciones que usted desearía haber ejecutado en todos los casos. Considere el siguiente ejemplo de comprobación de una contraseña para la validez:

 while ( !password.isValid() & (attempts++ < MAX_ATTEMPTS) ) { // re-prompt } 

Si la segunda condición no se evaluó debido a un cortocircuito, los attempts nunca se incrementarán. Por lo tanto, se habilita una mayor flexibilidad del progtwigdor.

Mi caso (C ++):

 void setFields(Parameters bundle) { if (setIfDifferent(&field1, bundle.value1) | setIfDifferent(&field2, bundle.value2) | setIfDifferent(&field3, bundle.value3)) { storeState(); } } 

setIfDifferent () establece el campo del objeto con nuevo valor si difieren, en cuyo caso devuelve verdadero; o devuelve falso en caso de que el campo y el nuevo valor sean los mismos. Por lo tanto, queremos intentar establecer todos los campos, y si alguno de ellos cambió, entonces queremos almacenar el estado del nuevo objeto.

Puede tener algunos efectos secundarios en la expresión lógica, por ejemplo, puede asignarlos simultáneamente con la verificación. Esto puede funcionar incorrectamente si solo se evalúa una parte.

No recuerdo el buen ejemplo ahora, pero recuerde que a veces necesitaba operadores “sin cortocircuito”.

Hmmm …. A continuación está el ejemplo INCORRECTO, que no funcionará sin “cortocircuito” O:

 if( (object1=getInstance1()).getNumber() == 1 || (object2=getInstance2()).getNumber() == 2 ) { // do something which requires bot object1 and object2 assigned } 

En mi caso, tengo dos métodos que comparan dos objetos diferentes pero relacionados (Object2 es un atributo de Object1) para ver si hubo algún cambio. Debe actualizarse si se actualizan, pero ambos deben evaluarse para que los objetos se modifiquen si se han modificado ambos. Por lo tanto, se requiere una comparación de tubería única “O”.

EX:

 if (compare(object1, currentObject1) | comparison(object2, currentObject2)) { updateObject1(object1); } 

Técnicamente, & y | no son lógicos, son operadores bit a bit que se convierten en operadores lógicos cuando se asocian con booleanos.

Hay momentos en los que desearía incluir expresiones de asignación dentro de sus expresiones lógicas.

Decir:

 if(a = (checkForSomeCondition()) | b = checkForAnotherCondition()) { //now do something here with a and b that has been cached } 

Si hubiera usado ||, no podría realizar la verificación anterior y habría tenido que dividir las tareas en declaraciones separadas. Nunca me he encontrado con escenarios como este durante el desarrollo de aplicaciones, pero me he encontrado varias veces al escribir algoritmos.

Por supuesto, podría usar operadores unarios en las expresiones lógicas o pasar variables por referencia a un predicado, pero esos parecen casos menos comunes que los anteriores.