2010-10-18 13 views
14

duplicados posibles:
Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=)
Why does a “&&=” Operator not exist?&& = y = || operadores

Hoy en el trabajo me escribió lo siguiente LOC (las identidades reales de B y B1 son confidenciales:)

b &&= b1; // meaning b = b && b1; 

Lo miré por un par de segundos y se dio cuenta de que no existe tal operador. Solo para estar seguro, hice clic en compilar y falló. Estar muerto seguro de que consulté el estándar.

¿Existen razones específicas por las que no existen tales operadores? Se me ocurren algunos:

  1. b &&= b1 y b = b && b1 puede no ser equivalente a causa de la evaluación de cortocircuito de & &.
  2. & & = es feo
  3. & & = rara vez es necesaria

No pretendo que sería muy útil disponer de este tipo de operadores, no. Tampoco afirmo que alguna o todas las tres razones anteriores no sean suficientes para evitar crear ese operador. Mi pregunta es la siguiente: ¿hay alguna razón mucho más seria que estoy supervisando?

+0

Sí, puede tener dos valores booleanos "verdaderos" (ambos mayores que uno), donde su valor bit a bit es "falso" ... Pruebe en modo bit y 2 y 1 y obtendrá 0 (falso), donde una lógica y produciría true – LorenVS

+2

'b & = isSomethingWithSideEffects();' ejecutaría la función independientemente. pero si se cambiara a '&& =' presumiblemente no lo sería en el caso de que b fuera falso, ¿no? – Dusty

+1

Lo siento, no entiendo por qué el comentario de Dingo ha sido votado. ¿Podría alguien explicar por favor? – John

Respuesta

8

No sé por qué tanto la pregunta como algunas respuestas mencionan el comportamiento de cortocircuito de los operadores lógicos correspondientes como un problema potencial.

No hay ningún problema relacionado con el cortocircuito en la definición de los operadores &&= y ||=. Deben definirse uniformemente con += y otros operadores similares, lo que significa que a &&= b debe ser equivalente a a = a && b, pero con a siendo evaluado solo una vez en la versión &&=. Esto significa, a su vez, que b no se evalúa en absoluto si a es originalmente cero. Fácil.

Entonces, la única razón por la que no existen en el idioma es, bueno, "solo porque".

+1

Exactamente. Perl tiene estos operadores, con ese comportamiento; y aunque he escuchado muchas críticas a Perl, nunca escuché a nadie quejarse de que '&& =' sea confuso. – Porculus

+0

Buen punto acerca de la cuestión del cortocircuito, pero técnicamente hablando a = a + b no es equivalente a a + = b si a tiene efectos secundarios, p. es una función que imprime algo y devuelve una referencia (en el primer caso se imprimirá dos veces y en el segundo solo una vez). –

+0

@Armen Tsirunyan: Bueno, no estaba tratando de hacerlo formalmente prefecto. El estándar de lenguaje define 'a + = b' como equivalente a' a = a + b', excepto que en '+ =' versión 'a' se evalúa solo una vez. De la misma manera, se puede definir '&& ='. – AnT

0

EDIT: el lenguaje incorrecto, pero todavía se aplica

Estoy de acuerdo con sus tres razones, aunque hay un escenario en el que he lamentado la falta de este operador, al escribir rutinas de deserialización personalizado. En un par de casos en los que un objeto incorrectamente serializado no era realmente "excepcional" (y para evitar la sobrecarga de excepción en C# para fallas muy comunes), usaría valores de retorno booleanos para indicar si una operación de deserialización fue exitosa.

Este código es completamente teórico, y Nested1, Nested2 y Nested3 son todas las estructuras:

public struct ComplexStruct 
{ 
    private Nested1 nested1; 
    private Nested2 nested2; 
    private Nested3[] nested3; 

    public bool Read(Reader reader) 
    { 
     bool ret = true; 
     int nested3Length = 0; 

     ret &&= nested1.Read(reader); 
     ret &&= nested2.Read(reader); 
     ret &&= reader.ReadInt32(ref nested3Length); 

     for(int i = 0; (ret && i < nested3Length); i++) 
     { 
      ret &&= nested3[i].Read(reader); 
     } 

     return ret; 
    } 
} 
+0

Bueno, ese era casi el mismo escenario cuando lo necesitaba (la parte del bucle). Ahora voy a editar mi pregunta para aclarar que –

+0

En ese caso, podría simplemente 'devolver falso;' temprano. –

+0

Resistí mi pregunta :) –

9

yo los he querido antes también. Dudo que la fealdad fuera en sí misma el factor determinante, el comportamiento en cortocircuito es el mejor argumento contra ellos que he escuchado hasta ahora.

Otro factor que contribuye es que C está diseñado para operar cerca del metal, casi todos los operadores corresponden directamente a una instrucción en las principales arquitecturas. No creo que haya una instrucción en x86, PPC, etc. que implemente directamente b &&= b1;

+1

+1. Las operaciones disponibles en el PDP-11 probablemente sean más determinantes, pero sigo pensando que estás buscando algo allí. –

+0

@ T.E.D .: Por supuesto, pero las arquitecturas principales modernas heredan la mayor parte de sus instrucciones de las arquitecturas de antaño. Especialmente en las áreas comunes. –

+0

¿Eh? El cortocircuito es el argumento * para * ellos. Sin eso, simplemente use '& =' con valores booleanos. En cuanto a las instrucciones, se usan las mismas para 'b && (b = b1);', (pero con una sola evaluación de 'b' por supuesto). El compilador elige entre una rama y una Y a nivel de bit. – Potatoswatter

1

Personalmente, votaría por la primera justificación con la que fue. Los operadores booleanos tienen semántica de cortocircuito, lo que podría dar lugar a situaciones realmente difíciles si se traducen en operadores de asignación. O ya no los convierte en cortocircuito o crea un extraño operador de asignación "opcional" (haga las cosas de la derecha y asigne en el resultado solo si el valor en el LHS ya no es cero). De cualquier forma, crearía errores sutiles porque las personas esperarían el otro comportamiento.

2

La razón principal por la que los operadores no existen es probablemente que K & R no pensó en ninguna forma atractiva de definirlos. También a veces quería un operador -> = (ptr -> = next sería equivalente a ptr = ptr-> lo que sea).

Un problema creo que con & & = es que no es obvio cuál de las siguientes sería más útil, o lo que se supone que debe ser:

 
    if (lhs && rhs) lhs = 1; else lhs = 0; 
    if (!rhs) lhs = 0; else lhs = !(!lhs)); 
    if (lhs && !rhs) lhs = 0; 
    if (!rhs) lhs = 0; 
La primera variación es la más claramente sugerida por la sintaxis, pero a partir de Desde un punto de vista práctico, si ninguno de los términos es cero, a menudo sería más útil dejar el lado izquierdo solo que establecerlo en "1".

BTW, a menudo he deseado una variación del operador de coma que evalúe el lado izquierdo, guarde el valor, luego evalúe el lado derecho y devuelva el valor del lado izquierdo. Equivalente a:

 
int foo(int p1, int p2) return p1; 
excepto aplicable a cualquier tipo (p2 no tiene que ser del mismo tipo que p1 y podría ser nulo) y con una orden de evaluación de izquierda a derecha garantizada. Sería muy útil para cosas como la indexación posterior al incremento con un paso que no sea unitario, por ejemplo, arr [ptr ~, ptr + = 2]; o para ciertos tipos de operaciones de intercambio de datos, por ejemplo, var1 = (var2 ~, var2 = var1); etc.

+3

En C, todos los operadores de asignación compuesta ('op =') se definen como 'lhs = lhs ops rhs' con la expresión' lhs' siendo evaluada solo una vez. Así que creo que hay poca ambigüedad en cuanto a cómo se definiría '&& =' (de la misma manera). –

+0

@Michael Burr: Esa sería, sinónicamente, la implementación natural, pero en la práctica hay veces que la tercera sería más útil que la primera, pero no puedo pensar en tantas como la primera sería realmente más útil. – supercat

+1

Propuse este equivalente a una pregunta ahora eliminada: 'if (lhs) lhs = (rhs! = 0);' Parece tener el comportamiento esperado de cortocircuito. Sin embargo, probablemente sea más rápido realizar 'if (lhs) lhs = rhs;' que también cortocircuita pero no coacciona todos los rhs distintos de cero a 1. –

2

Debido a que el resultado de a && b es siempre 0 o 1, creo que la interpretación de esto sólo sería inequívoco para el tipo C99 _Bool. Como esto no existía en el momento en que se creó C, este operador no se incluyó. Y hoy en día, nadie agrega fácilmente otro operador a C, ya que esto tendría un impacto en todos los analizadores existentes.