¿Debo usar paréntesis en sentencias lógicas aun cuando no sea necesario?

91

Digamos que tengo una condición booleana a AND b OR c AND d y estoy usando un lenguaje donde AND tiene un orden de operación superior al de OR . Podría escribir esta línea de código:

If (a AND b) OR (c AND d) Then ...

Pero en realidad, eso es equivalente a:

If a AND b OR c AND d Then ...

¿Hay algún argumento a favor o en contra que incluya paréntesis extraños? ¿La experiencia práctica sugiere que vale la pena incluirlos por legibilidad? ¿O es una señal de que un desarrollador necesita realmente sentarse y confiar en los conceptos básicos de su lenguaje?

    
pregunta Jeff Bridgman 11.06.2013 - 16:59
fuente

14 respuestas

104

Los buenos desarrolladores se esfuerzan por escribir código que sea claro y correcto . Los paréntesis en los condicionales, incluso si no son estrictamente necesarios, ayudan con ambos.

En cuanto a claridad , piense en paréntesis como comentarios en el código: no son estrictamente necesarios y, en teoría, un desarrollador competente debería poder descifrar el código sin ellos. Y, sin embargo, estas señales son extremadamente útiles, porque:

  • Reducen el trabajo requerido para entender el código.
  • Proporcionan confirmación de la intención del desarrollador.

Además, los paréntesis adicionales, al igual que las sangrías, espacios en blanco y otros estándares de estilo, ayudan a organizar visualmente el código de una manera lógica.

En cuanto a corrección , las condiciones sin paréntesis son una receta para los errores tontos. Cuando ocurren, pueden ser errores que son difíciles de encontrar, porque a menudo una condición incorrecta se comportará correctamente la mayor parte del tiempo y solo ocasionalmente fallará.

E incluso si lo hace bien, la siguiente persona que trabaje en su código puede no hacerlo, ya sea agregando errores a la expresión o entendiendo mal su lógica y, por lo tanto, agregando errores en otros lugares (como señala LarsH correctamente).

Siempre uso paréntesis para expresiones que combinan and y or (y también para operaciones aritméticas con problemas de precedencia similares).

    
respondido por el user82096 12.06.2013 - 15:35
fuente
89

No importa si usted tiene confianza en su comprensión del idioma. Lo que importa más es la comprensión del lenguaje del n00b que te sigue.

Escriba su código de la manera más clara y sin ambigüedades posible. Paréntesis extra a menudo (pero no siempre) ayuda. Poner una sola frase en una línea a menudo ayuda. La consistencia en el estilo de codificación a menudo ayuda.

Hay demasiados paréntesis, pero es una de esas situaciones en las que no necesitarás consejos: lo sabrás cuando lo veas. En ese punto, refactorice su código para reducir la complejidad de la declaración en lugar de eliminar el paréntesis.

    
respondido por el Dan Pichelman 06.03.2017 - 10:55
fuente
27

Siempre debes usar paréntesis ... no controlas el orden de prioridad ... el desarrollador del compilador sí lo hace. Aquí hay una historia que me sucedió sobre el no uso de paréntesis. Esto afectó a cientos de personas durante un período de dos semanas.

Razón del mundo real

He heredado una aplicación de marco principal. Un día, fuera del azul claro, dejó de funcionar. Eso es todo ... puf, simplemente se detuvo.

Mi trabajo era hacer que funcionara lo más rápido posible. El código fuente no se había modificado durante dos años, pero de repente simplemente se detuvo. Intenté compilar el código y se rompió en la línea XX. Miré la línea XX y no pude decir qué haría que la línea XX se rompiera. Pedí las especificaciones detalladas para esta aplicación y no había ninguna. La línea XX no fue la culpable.

Imprimí el código y comencé a revisarlo de arriba a abajo. Comencé a crear un diagrama de flujo de lo que estaba pasando. El código estaba tan complicado que casi no podía entenderlo. Me rendí tratando de hacer un diagrama de flujo. Tenía miedo de hacer cambios sin saber cómo ese cambio afectaría el resto del proceso, especialmente porque no tenía detalles de lo que hizo la aplicación o dónde estaba en la cadena de dependencia.

Entonces, decidí comenzar en la parte superior del código fuente y agregar frenos de línea blanca y de línea para hacer que el código sea más legible. Noté que, en algunos casos, existían condiciones que combinaban AND y OR, y no era claramente distinguible entre qué datos se ANDaban y qué datos se ORed. Así que empecé a poner paréntesis alrededor de las condiciones AND y OR para que sean más legibles.

A medida que avanzaba lentamente limpiándola, guardaba mi trabajo periódicamente. En un momento intenté compilar el código y algo extraño sucedió. El error había pasado la línea de código original y ahora estaba más abajo. Así que continué, esparciendo las condiciones AND y OR con parens. Cuando terminé de limpiarlo funcionó. Go Figure.

Entonces decidí visitar la tienda de operaciones y preguntarles si habían instalado recientemente algún componente nuevo en el marco principal. Dijeron que sí, recientemente hemos actualizado el compilador. Hmmmm.

Resulta que el antiguo compilador evaluó la expresión de izquierda a derecha independientemente. La nueva versión del compilador también evaluó expresiones de izquierda a derecha pero el código ambiguo, lo que significa que no se pudo resolver una combinación poco clara de AND y OR.

Lección que aprendí de esto ... SIEMPRE, SIEMPRE, SIEMPRE use parens para separar las condiciones AND las condiciones OR cuando se usan en conjunción entre sí.

Ejemplo simplificado

SI Producto = 191 O Producto = 193 Y Modelo="ABC" O Producto = 201 O Producto = 202 Y Modelo="DEF" ... (código lleno de varios de estos)

Esta es una versión simplificada de lo que encontré. También hubo otras condiciones con sentencias lógicas booleanas compuestas.

Recuerdo haberlo cambiado a:
IF ((Producto = 191 O Producto = 193) Y Modelo="ABC") O ((Producto = 201 O Producto = 202) Y Modelo="DEF") ...

No pude reescribirlo porque no había especificaciones. El autor original ya se había ido. Recuerdo presión intensa. Un barco de carga completo quedó varado en el puerto y no se pudo descargar porque este pequeño programa no funcionó. Sin advertencia. No hay cambios en el código fuente. Solo se me ocurrió preguntar a las Operaciones de la Red si modificaron algo después de que noté que agregar parens cambió los errores.

    
respondido por el Michael Riley - AKA Gunny 20.10.2018 - 12:40
fuente
17

Sí, si hay 'y' y 'o' mezclados.

También es una buena idea para () lo que es lógicamente una comprobación.

Aunque lo mejor es usar funciones de predicado bien nombradas y desalojar la mayoría de las comprobaciones y condiciones, dejándolas simples y legibles.

    
respondido por el Balog Pal 11.06.2013 - 16:21
fuente
11

Los paréntesis son semánticamente redundantes, por lo que al compilador no le importa, pero es una pista falsa: la verdadera preocupación es la legibilidad y comprensión del programador.

Voy a tomar la posición radical aquí y le daré un caluroso "no" a los paréntesis en a AND b OR c AND d . Todo programador debe saber de memoria que la precedencia en las expresiones booleanas va NO > Y > O , como recordar a para expresiones algebraicas. La puntuación redundante solo agrega desorden visual la mayor parte del tiempo en el código sin beneficio en la legibilidad del programador.

Además, si siempre usas paréntesis en expresiones lógicas y algebraicas, entonces renuncias a la posibilidad de usarlos como un marcador para "algo complicado está pasando aquí, ¡cuidado!" Es decir, en los casos en los que desea anular la prioridad predeterminada y haber evaluado la adición antes de la multiplicación, o OR antes de AND, los paréntesis son una buena bandera roja para el siguiente programador. Demasiado uso de ellos cuando no son necesarios, y te conviertes en el lobo del niño que lloró.

Haría una excepción para cualquier cosa fuera del ámbito del álgebra (booleana o no), como las expresiones de puntero en C, donde cualquier cosa más complicada que las expresiones estándar como *p++ o p = p->next debería estar entre paréntesis para mantener La desreferenciación y la recta aritmética. Y, por supuesto, nada de esto se aplica a lenguajes como Lisp, Forth o Smalltalk que usan alguna forma de notación polaca para las expresiones; pero para la mayoría de los lenguajes principales, la prioridad lógica y aritmética están totalmente estandarizadas.

    
fuente
8

Como yo lo veo:

SÍ Ventajas:

  • El orden de las operaciones es explícito.
  • Lo protege de futuros desarrolladores que no entienden el orden de las operaciones.

SÍ Contras:

  • Puede resultar en un código desordenado y difícil de leer

NO Ventajas:

  • ?

NO Contras:

  • El orden de las operaciones está implícito
  • El código es menos mantenible para los desarrolladores sin una buena comprensión del orden de las operaciones.
respondido por el MetaFight 11.06.2013 - 16:38
fuente
3
  

¿Hay algún argumento a favor o en contra que incluya paréntesis extraños? ¿La experiencia práctica sugiere que vale la pena incluirlos por legibilidad? ¿O es una señal de que un desarrollador necesita realmente sentarse y confiar en los conceptos básicos de su lenguaje?

Si nadie más tuviera que mirar mi código otra vez, no creo que me importaría.

Pero, desde mi experiencia:

  • Miro mi código de vez en cuando (a veces años después de escribirlo)
  • Otros a veces miran mi código
    • ¡O incluso hay que expandirlo / arreglarlo!
  • Ni yo ni el otro recuerdan exactamente lo que estaba pensando cuando lo escribí
  • El código "minizar el recuento de caracteres" de escritura críptico daña la legibilidad

Casi siempre hago esto porque confío en mi capacidad para leer rápidamente y no cometer pequeños errores mucho más con los parens que con ninguna otra cosa.

En tu caso, casi seguro que haría algo como:

if (a AND b) then ab = true
if (c AND d) then cd = true
If (ab OR cd) Then ...

Sí, es más código. Sí, puedo hacer operadores bool de lujo en su lugar. No, no me gusta la oportunidad cuando hojeo el código de 1+ años en el futuro, leo mal los operadores bool fantasia. ¿Qué pasaría si estuviera escribiendo código en un idioma que tenía diferente precedencia Y / O y tuve que retroceder para solucionar esto? ¿Voy a decir "¡Aha! ¡Recuerdo esta pequeña cosa inteligente que hice! No tuve que incluir parens cuando escribí esto el año pasado, ¡bueno, ahora me acuerdo!" si eso sucede (o, lo que es peor, ¿alguien más que no estaba al tanto de esta astucia o que fue arrojado a una situación de tipo "arreglar lo antes posible")?

Separarse con () hace que sea mucho más sencillo hojear y entender rápidamente más adelante ...

    
respondido por el enderland 11.06.2013 - 21:40
fuente
2

Caso general

En C #, la multiplicación y la división tienen prioridad sobre la suma y la resta.

Aún así, StyleCop, una herramienta que impone un estilo común en la base de código con un objetivo adicional para mitigar el riesgo de errores de introducción por código que puede no ser lo suficientemente claro, tiene el regla SA1407 . Esta regla producirá una advertencia con un código como este:

var a = 1 + 2 * 3;

Está claro que el resultado es 7 y no 9 , pero aún así, StyleCop sugiere poner entre paréntesis:

var a = 1 + (2 * 3);

Tu caso particular

En su caso particular, hay una precedencia de AND en comparación con OR en el idioma particular que usa.

No es así como se comportan todos los idiomas. Muchos otros tratan a AND y OR por igual.

Como desarrollador que trabaja principalmente con C #, cuando vi tu pregunta la primera vez y leí el código sin leer lo que escribiste antes, mi primera tentación fue comentar que las dos expresiones no son lo mismo. Con suerte, he leído toda la pregunta por completo antes de comentar.

Esta particularidad y el riesgo de que algunos desarrolladores creen que AND y OR tienen la misma prioridad hace que sea aún más importante agregar paréntesis.

No escriba código con el objetivo de demostrar que es inteligente. Escriba el código con un objetivo de legibilidad, incluso por personas que no estén familiarizadas con todos los aspectos del lenguaje.

    
respondido por el Arseni Mourzenko 11.06.2013 - 21:44
fuente
1

Como todos dijeron, use paréntesis cada vez que haga que la expresión sea más legible. Sin embargo, si la expresión es complicada, aconsejaría introducir nuevas funciones para las subexpresiones .

    
respondido por el Honza Brabec 12.06.2013 - 08:59
fuente
0
  

¿O es una señal de que un desarrollador necesita realmente sentarse y convertirse   ¿Confía en los conceptos básicos de su idioma?

Si usa estrictamente language en singular, quizás. Ahora toma todos los idiomas que conoces, desde los tiempos más antiguos hasta los más modernos, desde los compilados a los scripts, a los SQL y a tu propio DSL que inventaste el mes pasado.

¿Recuerda las reglas de precedencia exactas para cada uno de estos idiomas, sin mirar?

    
respondido por el Secure 11.06.2013 - 21:13
fuente
0

"Debo usar paréntesis en sentencias lógicas incluso cuando no sea necesario".

Sí, porque dos personas las encontrarán útiles:

  • El siguiente programador, cuyo conocimiento, competencia o estilo puede ser diferente

  • ¡El futuro que vuelva a este código en una fecha posterior!

respondido por el Michael Durrant 16.06.2013 - 16:20
fuente
-1

Los condicionales complejos son "álgebra booleana", que escribes de alguna manera que, bueno, hacen que se vea muy exactamente como álgebra, y definitivamente usarías parens para algebra , no usted?

Las reglas realmente útiles son las de negación:

!(A || B) <=> !A && !B
!(A && B) <=> !A || !B

O, en un formato un poco más claro:

!(A + B) <=> !A * !B
!(A * B) <=> !A + !B

que es realmente claramente solo álgebra cuando se escribe como:

-1*(A + B) = -A + -B
-1*(A * B) = -A * -B

Pero también podemos aplicar el pensamiento para la simplificación y expansión algebraica:

(A && B) || (C && D) => 
((A && B) || C) && ((A && B) || D) => 
(AC && BC) && (AD && BD) =>
AC && BC && AD && BD

aunque en código tienes que escribir:

(A||C) && (B||C) && (A||D) && (B||D)

o, en un formato un poco más claro:

(A + B) * (C + D) => 
((A + B) * C) + ((A + B) * D) => 
(AC + BC) + (AD + BD) =>
AC + BC + AD + BD

Básicamente, un condicional es solo una expresión algebraica, y al utilizar claramente entre paréntesis, puede aplicar más fácilmente las diversas reglas algebraicas que ya conoce a la expresión, incluido el concepto de "simplificar o expandir esta fórmula".

    
respondido por el Narfanator 12.06.2013 - 01:18
fuente
-1

Usaré paréntesis incluso si es opcional, porque ayuda a comprender mejor para todos, tanto para quien escribe el código como para el que está listo para ver ese código. En su caso, incluso los operadores booleanos tienen prioridad, podría funcionar bien al principio, pero no podemos decir que le ayudará en todos los casos. así que prefiero usar paréntesis en cualquier condición que pueda requerirlo u opcionalmente.

    
respondido por el singa selva sankar 14.06.2013 - 04:10
fuente
-1

Sí. Debe utilizar en cualquier caso cuando sienta que su código será más claro. Recuerde que su código debe ser lo suficientemente claro para que otros puedan entender sin leer sus comentarios dentro del código. Por lo tanto, es una buena práctica usar paréntesis y llaves. También tenga en cuenta que puede depender de la práctica particular de su empresa / equipo. Simplemente mantenga un enfoque y no mezcle.

    
respondido por el DeveloperArnab 27.06.2013 - 14:52
fuente

Lea otras preguntas en las etiquetas