Digamos que eu tenho uma condição booleana a AND b OR c AND d
e estou usando um idioma em AND
que uma ordem de operação maior é anterior a 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 se sentar e se tornar confiante no básico de seu idioma?
coding-style
operator-precedence
Jeff Bridgman
fonte
fonte
2 * 3 + 2
pode ser o mesmo,(2 * 3) + 2
mas o segundo é mais fácil de ler.Respostas:
Bons desenvolvedores se esforçam para escrever um código claro e correto . Parênteses em condicionais, mesmo que não sejam estritamente necessários, ajudam nos dois.
Quanto à clareza , pense nos 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:
Além disso, parênteses extras, 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 , condições sem parênteses são uma receita para erros tolos. Quando eles acontecem, podem ser difíceis de encontrar - porque geralmente uma condição incorreta se comporta corretamente na maioria das vezes, e apenas ocasionalmente falha.
E mesmo se você acertar, a próxima pessoa a trabalhar no seu código pode não, adicionando erros à expressão ou entendendo mal sua lógica e, assim, adicionando erros em outros lugares (como LarsH corretamente aponta).
Eu sempre uso parênteses para expressões que combinam
and
eor
(e também para operações aritméticas com problemas de precedência semelhantes).fonte
Importa menos se você está confiante em sua compreensão do idioma. O que importa mais é a compreensão do idioma do n00b que segue você.
Escreva seu código da maneira mais clara e inequívoca possível. Parênteses extras geralmente ajudam (mas nem sempre). Colocar apenas uma declaração em uma linha geralmente ajuda. A consistência no estilo de codificação geralmente ajuda.
Há muitos parênteses, mas é uma daquelas situações em que você não precisa de conselhos - você saberá quando vir. Nesse ponto, refatorar seu código para reduzir a complexidade da instrução em vez de remover parênteses.
fonte
There is such a thing as too many parenthesis
- você não é, obviamente, um lisper;)sim
Você sempre deve usar parênteses ... você não controla a ordem de precedência ... o desenvolvedor do compilador. Aqui está uma história que aconteceu comigo 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 aí ... só parou.
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. Tentei compilar o código e ele quebrou na linha XX. 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 era a culpada.
Imprimi o código e comecei a analisá-lo de cima para baixo. Comecei a criar um fluxograma do que estava acontecendo. O código era tão complicado que eu mal conseguia entender. Desisti de tentar fazer um fluxograma. Eu tinha medo de fazer alterações sem saber como essa alteração afetaria o restante do processo, principalmente porque não tinha detalhes do que o aplicativo fazia ou de onde estava na cadeia de dependência.
Então, decidi começar no topo do código-fonte e adicionar freios à linha branca e à espinha para tornar o código mais legível. Percebi que, em alguns casos, havia condições combinadas
AND
eOR
que não eram claramente distinguíveis entre quais dados estavam sendoAND
editados e quais estavam sendoOR
editados. Então comecei a colocar parênteses em torno das condiçõesAND
eOR
para torná-las mais legíveis.À medida que me afastava lentamente, eu periodicamente salvava meu trabalho. A certa altura, tentei compilar o código e aconteceu uma coisa estranha. O erro saltou da linha de código original e agora estava mais abaixo. Então eu continuei, speparating o
AND
eOR
condições com parênteses. Quando terminei de limpá-lo, funcionou. Vai saber.Decidi então visitar a loja de operações e perguntar se eles haviam instalado recentemente algum novo componente no chassi principal. Eles disseram que sim, recentemente atualizamos o compilador. Hmmmm.
Acontece que o compilador antigo avaliou a expressão da esquerda para a direita, independentemente. A nova versão do compilador também avaliou expressões do código da esquerda para a direita, mas ambíguo, o que significa uma combinação pouco clara
AND
eOR
não pôde ser resolvida.Lição que aprendi com isso ... SEMPRE, SEMPRE, SEMPRE use parênteses para separar
AND
condições eOR
condições quando usadas em conjunto.Exemplo simplificado
IF Product = 191 OR Product = 193 AND Model = "ABC" OR Product = 201 OR Product = 202 AND Model = "DEF" ...
(código repleto de várias delas)Esta é uma versão simplificada do que encontrei. Havia outras condições também com instruções lógicas booleanas compostas.
Lembro-me de encaminhá-lo para:
IF ((Product = 191 OR Product = 193) AND Model = "ABC") OR ((Product = 201 OR Product = 202) AND Model = "DEF") ...
Não pude reescrevê-lo porque não havia especificações. O autor original se foi há muito tempo. Lembro-me de uma pressão intensa. Um navio de carga inteiro estava preso no porto e não podia ser descarregado porque esse pequeno programa não funcionava. Nenhum aviso. Nenhuma alteração no código fonte. Só me ocorreu perguntar às Operações de Rede se elas modificaram alguma coisa depois que eu notei que adicionar parênteses alterava os erros.
fonte
Sim, se houver misto 'e' e 'ou'.
Também é uma boa idéia () o que é logicamente uma verificação.
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.
fonte
a AND b
provavelmente ser substituída por uma função ou um valor boolen pré-calculado que tenha um nome mais descritivo.Os parênteses são semanticamente redundantes, portanto o compilador não se importa, mas isso é um problema - a verdadeira preocupação é a legibilidade e compreensão do programador.
Vou assumir a posição radical aqui e dar um "não" caloroso aos parênteses
a AND b OR c AND d
. Todo programador deve saber de cor que a precedência nas expressões booleanas NÃO é E> OU , assim como lembrar Por favor, desculpe minha querida tia Sally por expressões algébricas. A pontuação redundante apenas adiciona confusão visual na maioria das vezes no código, sem nenhum benefício na legibilidade do programador.Além disso, se você sempre usa parênteses em expressões lógicas e algébricas, renuncia à capacidade de usá-los como um marcador de "algo complicado está acontecendo aqui - cuidado!" 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 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 Chorou Lobo.
Eu abriria uma exceção para qualquer coisa fora do domínio da álgebra (booleano ou não), como expressões de ponteiro em C, onde algo mais complicado que expressões idiomáticas padrão como
*p++
oup = p->next
provavelmente deveria ser colocado entre parênteses para manter a desreferenciação e a aritmética retas. E, é claro, nada disso se aplica a idiomas como Lisp, Forth ou Smalltalk que usam alguma forma de notação polonesa para expressões; mas para a maioria das linguagens convencionais, a precedência lógica e aritmética é totalmente padronizada.fonte
AND
vsOR
é um caso bastante básico que eu gostaria que os outros desenvolvedores da minha equipe soubessem. Eu me preocupo que às vezes "usar parênteses para maior clareza" seja realmente "usar parênteses para que eu nunca precise me preocupar em aprender a precedência"..member
antes de operadores unários, unárias antes de operadores binários,*
e/
antes+
e-
antes<
e>
e==
antes&&
antes||
antes da atribuição. Essas regras são fáceis de lembrar porque correspondem ao meu "senso comum" sobre como os operadores são normalmente usados (por exemplo, você não daria==
maior precedência do que+
ou1 + 1 == 2
para de trabalhar) e cobre 95% das questões de precedência que eu teria .Da maneira que eu vejo:
SIM Profissionais:
SIM Contras:
NÃO Profissionais:
NÃO Contras:
fonte
3 * a^2 + 2 * b^2
mais fácil ler do que(3 * (a^2)) + (2 * (b^2))
, porque o formato e a precedência são familiares e padrão. Da mesma forma, você pode (para ser extremo) proibir o uso de funções e macros (ou compiladores!) Para tornar a semântica do seu código mais explícita. Obviamente, não estou defendendo isso, mas espero responder à sua pergunta sobre por que precisa haver limitações (um equilíbrio) em tornar as coisas explícitas.Se ninguém mais tivesse que olhar para o meu código novamente, acho que não me importaria.
Mas, pela minha experiência:
Quase sempre faço isso porque confio na minha capacidade de ler rapidamente e não cometer pequenos erros muito mais com parênteses do que nada mais.
No seu caso, eu quase certamente faria algo como:
Sim, é mais código. Sim, eu posso fazer operadores bool chiques. Não, não gosto da chance de, ao ler o código mais de um ou mais anos no futuro, interpretar mal os operadores booliques sofisticados. E se eu estivesse escrevendo código em um idioma que tivesse precedência diferente de AND / OR e tivesse que voltar para corrigir isso? Eu vou dizer: "aha! Lembro-me dessa coisinha inteligente que fiz! Não precisei incluir parênteses quando escrevi este ano passado, coisa boa que 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 "conserte o mais rápido possível")?
Separar com () torna muito mais fácil deslizar e entender rapidamente mais tarde ...
fonte
ab = a AND b
?ab
permaneça inalterado, se nãoa AND b
.Caso Geral
Em C #, multiplicação e divisão têm precedência sobre adição e subtração.
Ainda assim, o StyleCop, uma ferramenta que aplica estilo comum em toda a base de código com um objetivo adicional de mitigar o risco de erros introduzidos por código que podem não ser suficientemente claros, possui a regra SA1407 . Esta regra produzirá um aviso com um pedaço de código como este:
É claro que o resultado é
7
e não9
, mas ainda assim, o StyleCop sugere colocar parênteses:Seu caso particular
No seu caso particular, há uma precedência de AND em comparação com OR no idioma específico que você usa.
Não é assim que todo idioma 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. Felizmente, li toda a pergunta antes de comentar.
Essa particularidade e o risco de alguns desenvolvedores acreditarem que AND e OR têm a mesma prioridade torna ainda mais importante adicionar parênteses.
Não escreva código com o objetivo de mostrar que você é inteligente. Escreva um código com o objetivo de facilitar a leitura, inclusive por pessoas que talvez não estejam familiarizadas com todos os aspectos do idioma.
fonte
Como todos disseram, use parênteses sempre que tornar a expressão mais legível. No entanto, se a expressão for complicada, aconselho a introduzir novas funções para as subexpressões .
fonte
Se você usa estritamente a linguagem no singular, talvez. Agora leve todas as linguagens que você conhece, desde as mais antigas até as mais modernas, desde compiladas até scripts para SQL até sua própria DSL que você inventou no mês passado.
Você se lembra das regras de precedência exata para cada um desses idiomas, sem olhar?
fonte
"Devo usar parênteses em declarações lógicas mesmo quando não for necessário."
Sim, porque duas pessoas os acharão úteis:
O próximo programador, com conhecimento, competência ou estilo pode ser diferente
O futuro você que retorna a este código em uma data posterior!
fonte
Condicionais complexos são "álgebra booleana", que você escreve de várias maneiras que, bem, fazem com que pareça exatamente exatamente com álgebra, e você definitivamente usaria parênteses para álgebra , não é?
As regras realmente úteis são as negativas:
Ou, em um formato um pouco mais claro:
que é realmente claramente apenas álgebra quando escrito como:
Mas também podemos aplicar o pensamento para simplificação e expansão algébrica:
embora no código você precise escrever:
ou, em um formato um pouco mais claro:
Basicamente, um condicional ainda é apenas uma expressão algébrica e, usando claramente parênteses, você pode aplicar mais facilmente as várias regras algébricas que você já conhece à expressão, incluindo o conceito antigo de "simplificar ou expandir esta fórmula".
fonte
!(A + B) <=> !A + !B
e-1*(A + B) = -A + -B
o operador não deveria ter sido mudado de+
para*
na segunda expressão?Usarei parênteses, mesmo que seja opcional, porque porque 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 o ajudará em todos os casos. então eu prefiro o parêntese do usuário em qualquer condição que possa exigir ou opcionalmente.
fonte
Sim. Você deve usar em qualquer caso quando achar que seu código será mais claro. Lembre-se de que seu código deve ser claro o suficiente para que outras pessoas possam entender sem ler seus comentários dentro do código. Portanto, é uma boa prática usar parênteses e chaves. Lembre-se também de que isso pode depender da prática específica da sua empresa / equipe. Apenas mantenha uma abordagem e não se misture.
fonte