Devo usar parênteses em declarações lógicas, mesmo quando não é necessário?

91

Digamos que eu tenha uma condição booleana a AND b OR c AND d e estou usando um idioma em que AND tenha uma ordem de operação maior que precedente que OR . Eu poderia escrever esta linha de código:

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

Mas, na verdade, isso é equivalente a:

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

Existem argumentos a favor ou contra, incluindo os parênteses estranhos? A experiência prática sugere que vale a pena incluí-los para facilitar a leitura? Ou é um sinal de que um desenvolvedor precisa realmente sentar e se tornar confiante no básico de seu idioma?

    
por Jeff Bridgman 11.06.2013 / 16:59
fonte

14 respostas

104

Bons desenvolvedores se esforçam para escrever código que seja claro e correto . Parênteses em condicionais, mesmo que não sejam estritamente necessários, ajudam com ambos.

Quanto à clareza , pense em parênteses como comentários no código: eles não são estritamente necessários e, em teoria, um desenvolvedor competente deve ser capaz de descobrir o código sem eles. E, no entanto, essas dicas são extremamente úteis, porque:

  • Eles reduzem o trabalho necessário para entender o código.
  • Eles fornecem confirmação da intenção do desenvolvedor.

Além disso, parênteses extras, assim como recuos, espaços em branco e outros padrões de estilo, ajudam a organizar visualmente o código de maneira lógica.

Quanto à correção , as condições sem parênteses são uma receita para erros bobos. Quando eles acontecem, eles podem ser erros difíceis de serem encontrados - porque muitas vezes uma condição incorreta se comportará corretamente a maior parte do tempo, e só ocasionalmente falhará.

E mesmo se você acertar, a próxima pessoa a trabalhar em seu código pode não adicionar erros à expressão ou não entender sua lógica e, assim, adicionar erros em outro lugar (como LarsH corretamente aponta).

Sempre uso parênteses para expressões que combinam and e or (e também para operações aritméticas com problemas de precedência semelhantes).

    
por 12.06.2013 / 15:35
fonte
89

Importa menos se você está confiante em sua compreensão da linguagem. O que importa mais é a compreensão da linguagem do n00b que segue você.

Escreva seu código da maneira mais clara e inequívoca possível. Parêntese extra frequentemente (mas nem sempre) ajuda. Colocar apenas uma instrução em uma linha geralmente ajuda. Consistência no estilo de codificação geralmente ajuda.

Existem muitos parênteses, mas é uma daquelas situações em que você não precisa de conselhos - você saberá quando vir. Nesse ponto, refatore seu código para reduzir a complexidade da instrução, em vez de remover os parênteses.

    
por 06.03.2017 / 10:55
fonte
27

Sim

Você deve sempre usar parênteses ... você não controla a ordem de precedência ... o desenvolvedor do compilador faz. Aqui está uma história que me aconteceu sobre o não uso de parênteses. Isso afetou centenas de pessoas durante um período de duas semanas.

Razão do Mundo Real

Eu herdei um aplicativo de quadro principal. Um dia, do nada, parou de funcionar. É isso ... poof acabou de parar.

Meu trabalho era fazê-lo funcionar o mais rápido possível. O código-fonte não foi modificado por dois anos, mas de repente parou. Eu tentei compilar o código e ele quebrou na linha XX. Eu olhei para a linha XX e não sabia dizer o que faria a linha XX quebrar. Eu pedi as especificações detalhadas para esta aplicação e não havia nenhuma. A linha XX não foi a culpada.

Imprimi o código e comecei a revisá-lo de cima para baixo. Comecei a criar um fluxograma do que estava acontecendo. O código era tão confuso que eu mal conseguia entender. Eu desisti de tentar fazer o fluxograma. Eu estava com medo de fazer alterações sem saber como essa mudança afetaria o restante do processo, especialmente porque eu não tinha detalhes sobre o que o aplicativo fazia ou onde estava na cadeia de dependências.

Então, decidi começar no topo do código-fonte e adicionar whitespce e line brakes para tornar o código mais legível. Percebi que, em alguns casos, havia condições que combinavam ANDs e ORs e não eram claramente distinguíveis entre quais dados estavam sendo ANDed e quais dados estavam sendo ORed. Então comecei a colocar parênteses em torno das condições AND e OR para torná-las mais legíveis.

Como eu lentamente abaixei a limpeza, eu periodicamente salvaria meu trabalho. Em um ponto eu tentei compilar o código e uma coisa estranha aconteceu. O erro saltou na linha original do código e agora estava mais baixo. Então continuei, separando as condições AND e OR com os parênteses. Quando terminei a limpeza, funcionou. Vá para a Figura.

Eu então decidi visitar a loja de operações e perguntar se eles tinham instalado recentemente novos componentes na estrutura principal. Eles disseram sim, nós recentemente atualizamos o compilador. Hmmmm.

Acontece que o compilador antigo avaliava a expressão da esquerda para a direita, independentemente. A nova versão do compilador também avaliava as expressões da esquerda para a direita, mas o código ambíguo, o que significa que a combinação não clara de ANDs e ORs não pôde ser resolvida.

Lição que aprendi com isso ... SEMPRE, SEMPRE use SEMPRE os parênteses para separar as condições AND e as condições OR quando eles são usados em conjunção um com o outro.

Exemplo simplificado

Produto IF = 191 OR Produto = 193 E modelo="ABC" ou produto = 201 OR Produto = 202 E modelo="DEF" ... (código repleto de vários destes)

Esta é uma versão simplificada do que encontrei. Havia outras condições com instruções lógicas booleanas compostas também.

Lembro-me de mandar para:
SE ((Produto = 191 OR Produto = 193) E Modelo="ABC") OR ((Produto = 201 OR Produto = 202) E Modelo="DEF") ...

Eu não pude reescrevê-lo porque não havia especificações. O autor original foi embora há muito tempo. Eu me lembro de uma pressão intensa. Um navio de carga inteiro estava encalhado no porto e não podia ser descarregado porque este pequeno programa não funcionava. Nenhum aviso. Nenhuma alteração no código-fonte. Só me ocorreu perguntar ao Network Operations se eles modificaram alguma coisa depois que eu notei que adicionar parens alterou os erros.

    
por 20.10.2018 / 12:40
fonte
17

Sim, se houver misto 'e' e 'ou'.

Também é uma boa ideia para () o que é logicamente um cheque.

Embora o melhor seja usar funções de predicado bem nomeadas e remover a maioria das verificações e condições, deixando-as simples e legíveis.

    
por 11.06.2013 / 16:21
fonte
11

Os parênteses são semanticamente redundantes, então o compilador não se importa, mas isso é um arenque vermelho - a preocupação real é a legibilidade e a compreensão do programador.

Vou tomar a posição radical aqui e dar um "não" caloroso aos parênteses em a AND b OR c AND d . Todo programador deve saber de cor que a precedência em expressões booleanas é NOT > AND > OR , como lembrar Por favor, desculpe Minha querida tia Sally para expressões algébricas. A pontuação redundante apenas acrescenta confusão visual na maioria das vezes no código, sem benefício na legibilidade do programador.

Além disso, se você sempre usa parênteses em expressões lógicas e algébricas, então você desiste de usá-las como um marcador para "algo complicado está acontecendo aqui - olhe para fora!" Ou seja, nos casos em que você deseja substituir a precedência padrão e ter a adição avaliada antes da multiplicação, ou o OR antes de AND, os parênteses são um bom sinalizador vermelho para o próximo programador. Muito uso deles quando não são necessários, e você se torna o Garoto que Chora Lobo.

Eu faria uma exceção para qualquer coisa fora da esfera da álgebra (booleana ou não), como expressões de ponteiro em C, onde qualquer coisa mais complicada do que expressões idiomáticas como *p++ ou p = p->next provavelmente deveria ser entre parênteses para manter a desreferenciação e a aritmética em linha reta. E, claro, nada disso se aplica a linguagens como Lisp, Forth ou Smalltalk que usam alguma forma de notação polonesa para expressões; mas para a maioria das principais línguas, a precedência lógica e aritmética é totalmente padronizada.

    
por 11.06.2013 / 20:37
fonte
8

Como eu vejo:

SIM Prós:

  • A ordem das operações é explícita.
  • Protege você de futuros desenvolvedores que não entendem a ordem das operações.

SIM Contras:

  • Pode resultar em código desordenado e difícil de ler

NÃO Prós:

  • ?

NÃO Contras:

  • A ordem das operações está implícita
  • O código é menos sustentável para desenvolvedores sem um bom entendimento da ordem das operações.
por 11.06.2013 / 16:38
fonte
3

Are there any arguments in for or against including the extraneous parentheses? Does practical experience suggest that it is worth including them for readability? Or is it a sign that a developer needs to really sit down and become confident in the basics of their language?

Se ninguém mais tivesse que ver meu código novamente, não acho que me importaria.

Mas, pela minha experiência:

  • Eu olho para o meu código novamente ocasionalmente (às vezes anos depois de escrevê-lo)
  • Outros às vezes olham para o meu código
    • Ou até mesmo expandir / corrigir isso!
  • Nem eu nem o outro nos lembramos exatamente do que eu estava pensando quando escrevi
  • Escrever código "minimizar o número de caracteres" criptografado prejudica a legibilidade

Eu quase sempre faço isso porque confio em minha capacidade de ler rapidamente e não cometer pequenos erros muito mais com parênteses do que com qualquer outra coisa.

No seu caso, eu quase certamente faria algo como:

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

Sim, é mais código. Sim, eu posso fazer operadores boolios em vez disso. Não, eu não gosto da chance quando o código de skimming 1 + anos no futuro eu interpretei operadores de bool extravagantes. E se eu estivesse escrevendo código em uma linguagem que tivesse diferente precedência AND / OR e tivesse que voltar para corrigir isso? Eu vou, "aha! Eu me lembro dessa coisinha inteligente que eu fiz! Eu não tive que incluir parênteses quando escrevi isso no ano passado, coisa boa que eu lembro agora!" se isso acontecer (ou pior, alguém que não estava ciente dessa inteligência ou foi jogado em uma situação do tipo "consertar o mais rápido possível")?

Separar com () faz com que seja muito mais fácil examinar e entender mais tarde ...

    
por 11.06.2013 / 21:40
fonte
2

Caso geral

Em C #, multiplicação e divisão têm precedência sobre adição e subtração.

Ainda assim, StyleCop, uma ferramenta que reforça o estilo comum em toda a base de código com um objetivo adicional de mitigar o risco de introdução de bugs por código que pode não estar suficientemente claro, tem o regra SA1407 . Essa regra produzirá um aviso com um código como este:

var a = 1 + 2 * 3;

É claro que o resultado é 7 e não 9 , mas ainda assim, StyleCop sugere colocar parênteses:

var a = 1 + (2 * 3);

Seu caso particular

No seu caso particular, há uma precedência de AND comparada a OR no idioma específico que você usa.

Não é assim que toda linguagem se comporta. Muitos outros tratam AND e OR igualmente.

Como desenvolvedor que trabalha principalmente com C #, quando vi sua pergunta pela primeira vez e li o trecho de código sem ler o que você escreveu antes, minha primeira tentação foi comentar que as duas expressões não são as mesmas. Espero ter lido toda a questão antes de comentar.

Essa particularidade e o risco de alguns desenvolvedores acreditarem que AND e OR têm a mesma prioridade tornam ainda mais importante adicionar parênteses.

Não escreva código com um objetivo para mostrar que você é inteligente. Escreva o código com uma meta de legibilidade, inclusive por pessoas que talvez não estejam familiarizadas com todos os aspectos do idioma.

    
por 11.06.2013 / 21:44
fonte
1

Como todos disseram, use parênteses toda vez que a expressão for mais legível. No entanto, se a expressão for complicada, aconselho a introduzir novas funções para as subexpressões .

    
por 12.06.2013 / 08:59
fonte
0

Or is it a sign that a developer needs to really sit down and become confident in the basics of their language?

Se você usar estritamente idioma no singular, talvez. Agora pegue todas as línguas que você conhece, desde as mais antigas até as mais modernas, desde compiladas até scripts à SQL, até a sua própria DSL que você inventou no mês passado.

Você se lembra das regras de precedência exatas para cada um desses idiomas, sem olhar?

    
por 11.06.2013 / 21:13
fonte
0

"Devo usar parênteses em declarações lógicas, mesmo quando não for necessário."

Sim, porque duas pessoas irão considerá-las úteis:

  • O próximo programador, quem é conhecimento, competência ou estilo, pode ser diferente

  • O futuro você que retorna a este código em alguma data posterior!

por 16.06.2013 / 16:20
fonte
-1

As condicionais complexas são "álgebra booleana", que você escreve de alguma forma que, bem, faz com que pareça exatamente com a álgebra, e você definitivamente usaria parêntesis para álgebra , não você?

As regras realmente úteis são as negativas:

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

Ou, em um formato um pouco mais claro:

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

que é realmente claramente apenas álgebra quando escrito como:

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

Mas também podemos aplicar o pensamento para a simplificação e expansão algébrica:

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

embora no código você tenha que escrever:

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

ou, em um formato um pouco mais claro:

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

Basicamente, uma condicional ainda é apenas uma expressão algébrica, e usando parênteses claramente, é mais fácil aplicar as várias regras algébricas que você já conhece à expressão, incluindo o conceito de "simplificar ou expandir essa fórmula".

    
por 12.06.2013 / 01:18
fonte
-1

Usarei parênteses mesmo que seja opcional, porque isso ajuda a entender melhor para todos, para quem escreve o código e para quem está pronto para ver esse código. No seu caso, mesmo os operadores booleanos têm precedência, pode funcionar bem no início, mas não podemos dizer que isso o ajudará em todos os casos. então eu prefiro parênteses do usuário em qualquer condição que possa exigir ou opcionalmente.

    
por 14.06.2013 / 04:10
fonte
-1

Sim. Você deve usar em qualquer caso quando sentir que seu código será mais claro. Lembre-se de que seu código deve ser claro o suficiente para que os outros possam entender sem ler seus comentários dentro do código. Portanto, é uma boa prática usar parênteses e chaves. Também tenha em mente que isso pode depender da prática específica de sua empresa / equipe. Apenas mantenha uma abordagem e não misture.

    
por 27.06.2013 / 14:52
fonte