Operador ternário considerado prejudicial? [fechadas]

77

Por exemplo, você preferiria essa frase única

int median(int a, int b, int c) {
    return (a<b) ? (b<c) ? b : (a<c) ? c : a : (a<c) ? a : (b<c) ? c : b;
}

ou uma solução if / else envolvendo várias declarações de retorno?

Quando é ?: apropriado e quando não é? Deve ser ensinado ou escondido de principiantes?

    
por FredOverflow 18.06.2013 / 19:56
fonte

25 respostas

229

Is the ternary operator evil?

Não, é uma bênção.

When is ?: appropriate?

Quando é algo tão simples, você não quer perder muitas linhas.

and when is it not?

Quando a legibilidade e a clareza do código sofrem e a possibilidade de um erro por meio de atenção insuficiente aumenta, por exemplo, com muitos operadores encadeados, assim como no seu exemplo.

O teste decisivo é quando você começa a duvidar de que seu código é facilmente legível e pode ser mantido a longo prazo. Então não faça isso.

    
por 20.08.2014 / 16:26
fonte
49

Eu acho que o operador ternário unnested (ou seja, uma declaração onde é usado apenas uma vez) é bom, mas se você está aninhando mais de um, torna-se um pouco difícil de ler.

    
por 21.12.2010 / 16:16
fonte
24

Quando é?: apropriado

  • Quando torna seu código mais conciso e legível.

e quando não é?

  • Quando isso torna seu código ilegível.
  • Se você está fazendo isso apenas para agradar uma ferramenta de refatoração como o ReSharper e não a pessoa que precisa manter o código

Se você tem alguma chamada lógica ou de função dentro da expressão ternária, está tornando horrível de se olhar.

    
por 20.12.2010 / 18:12
fonte
21

Uma diferença que (eu acho) ninguém apontou é que if-else não pode retornar um valor, enquanto o operador ternário pode.

Vindo do F #, às vezes gosto de usar o operador ternário para imitar a correspondência de padrões.

match val with
| A -> 1
| B -> 3
| _ -> 0

vs

return val == A ? 1 : 
       val == B ? 3 : 
       0;
    
por 26.11.2012 / 07:15
fonte
12

Um exemplo (IMHO) de um uso válido:

printf("Success in %d %s\n", nr_of_tries, (nr_of_tries == 1 ? "try" : "tries"));

Isso resulta em código mais legível do que ter duas instruções de impressão distintas. Exemplos aninhados dependem: (compreensível? Sim: não)

    
por 20.12.2010 / 20:07
fonte
5

Absolutamente não é mal. De fato, é puro , e se-então-senão não é.

Em linguagens funcionais como Haskell, F #, ML etc., são as declarações if-then-else que são consideradas más.

A razão para isso é que qualquer "ação" como uma instrução imperativa if-then-else requer que você separe uma declaração de variável de sua definição e introduza state para sua função.

Por exemplo, no código a seguir:

const var x = n % 3 == 1
    ? Parity.Even
    : Parity.Odd;

vs.

Parity x;
if (n % 3 == 1)
    x = Parity.Even;
else
    x = Parity.Odd;

O primeiro tem duas vantagens além de ser mais curto:

  1. x é uma constante e, portanto, oferece muito menos chances de introduzir bugs e pode ser potencialmente otimizado de maneiras que o segundo nunca poderia ser.
  2. O tipo é claro pela expressão, portanto, o compilador pode facilmente inferir que x precisa ser do tipo Parity .

Confusamente, em linguagens funcionais, o operador ternário é geralmente chamado de se-então-else. Em Haskell, você pode dizer x = if n mod 3 == 1 then Odd else Even .

    
por 21.12.2010 / 15:56
fonte
5

Essa expressão em particular faz meus olhos doerem; Eu atacaria qualquer desenvolvedor da minha equipe que o usasse porque é inatingível.

Operadores ternários não são maus quando bem usados. Eles nem precisam ser linhas simples; Um longo que é bem formatado pode ser muito claro e fácil de entender:

return
      ( 'a' == $s ) ? 1
    : ( 'b' == $s ) ? 2
    : ( 'c' == $s ) ? 3
    :                 4;

Eu gosto disso melhor do que o equivalente se / then / else cadeia:

if ( 'a' == $s ) {
    $retval = 1;
}
elsif ( 'b' == $s ) {
    $retval = 2;
}
elsif ( 'c' == $s ) {
    $retval = 3;
}
else {
    $retval = 4;
}

return $retval;

Vou reformatá-los em:

if    ( 'a' == $s ) { $retval = 1; }
elsif ( 'b' == $s ) { $retval = 2; }
elsif ( 'c' == $s ) { $retval = 3; }
else                { $retval = 4; }

return $retval;

se as condições e atribuições permitirem um alinhamento fácil. Ainda prefiro a versão ternária porque é mais curta e não tem tanto ruído em torno das condições e atribuições.

    
por 22.12.2010 / 07:51
fonte
3

ReSharper no VS.NET algumas vezes sugere a substituição de if...else pelo operador ?: .

Parece que o ReSharper sugere apenas se as condições / blocos estão abaixo de um certo nível de complexidade, caso contrário, ele fica com if...else .

    
por 20.12.2010 / 21:58
fonte
2

Isso pode ser reformatado para ficar tão bonito quanto a combinação if / else:

int median(int a, int b, int c)
{
    return
        (a<b)
        ?
            (b<c)
            ? b
            :
                (a<c)
                ? c
                : a
        :
            (a<c)
            ? a
            :
                (b<c)
                ? c
                : b;
}

Mas o problema é que não tenho certeza se consegui o recuo certo para representar o que realmente acontecerá. : -)

    
por 20.12.2010 / 23:07
fonte
2

Longe de ser mau, o operador ternário é uma dádiva de Deus.

  • É mais útil quando você quer tomar uma decisão em uma expressão aninhada . O exemplo clássico é uma chamada de função:

    printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
    
  • Em seu exemplo específico, o ternário é quase gratuito, pois é a expressão de nível superior em return . Você pode elevar a condição para o nível de instrução sem duplicar nada além da palavra-chave return .

N.B. Nada tornará esse algoritmo específico para mediana fácil de ler.

    
por 21.12.2010 / 03:55
fonte
2
  1. Argumentos "maus" à parte, na minha experiência eu encontrei uma alta correlação entre o uso de um programador do operador ternário e a probabilidade de toda sua base de código ser difícil de ler, seguir e manter (se não completamente indocumentado). Se um programador está mais preocupado em salvar algumas linhas de 1 a 2 caracteres do que alguém ser capaz de entender seu código, então qualquer confusão menor que compreenda uma declaração ternária é geralmente a ponta do iceberg.

  2. Operadores ternários atraem números mágicos como o s ** t atrai moscas.

Se eu estivesse procurando uma biblioteca Open Source para resolver um problema em particular, e eu visse código como os operadores ternários do pôster original em um candidato para a dita biblioteca, os sinos de aviso começariam a surgir na minha cabeça e eu começaria considerando mudar para outro projeto para emprestar.

    
por 21.12.2010 / 18:12
fonte
2

Veja um exemplo de quando é maligno:

oldValue = newValue >= 0 ? newValue : oldValue;

É confuso e desperdício. O compilador poderia otimizar a segunda expressão (oldValue = oldValue), mas por que o codificador fez isso em primeiro lugar?

Outro doozy:

thingie = otherThingie != null ? otherThingie : null;

Algumas pessoas não pretendem ser codificadores ...

Greg diz que a declaração if equivalente é "barulhenta". É se você escrever ruidosamente. Mas isso mesmo se pode ser escrito como:

if ('a' == $s) return 1;
if ('b' == $s) return 2;
if ('c' == $s) return 3;
return 4;

Que não é mais ruidoso que o ternário. Eu me pergunto se os atalhos ternários; todas as expressões são avaliadas?

    
por 26.01.2011 / 00:21
fonte
2

Malvado? Olha, eles são apenas diferentes.

if é uma declaração. (test ? a : b) é uma expressão. Eles não são a mesma coisa.

Existem expressões para expressar valores. Existem instruções para executar ações. Expressões podem aparecer dentro de instruções, mas não vice-versa. Assim, você pode usar expressões ternárias dentro de outras expressões, como para termos em uma soma, ou para argumentos para um método, e assim por diante. Você não precisa , mas você pode se você quiser . Não há nada de errado com isso. Algumas pessoas podem dizer que é mal, mas essa é a opinião deles.

Um valor de uma expressão ternária faz com que você lide com casos verdadeiros e falsos. if declarações não.

Se você estiver preocupado com a legibilidade, poderá formatá-los de maneira legível.

De alguma forma, o "mal" penetrou no vocabulário de programação. Eu adoraria saber quem primeiro caiu. (Na verdade, eu tenho um suspeito - ele está no MIT.) Eu preferiria que tivéssemos razões objetivas para juízos de valor nesse campo, não apenas o gosto e o xingamento das pessoas.

    
por 26.01.2011 / 02:17
fonte
1

Tem um lugar. Eu trabalhei em muitas empresas onde os níveis de habilidade dos desenvolvedores variam de péssimo a bruxo. Já que o código tem que ser mantido, e eu não estarei lá para sempre, eu tento escrever coisas para que pareça que ele pertence lá (sem olhar para os comentários com as minhas iniciais, é extremamente raro você poder olhe para o código em que trabalhei para ver onde fiz as alterações), e que alguém com menos habilidade do que eu possa mantê-lo.

Enquanto o operador ternário parece nitziffic e bem legal, minha experiência é que essa linha de código será praticamente impossível de manter. No meu atual empregador, temos produtos que são enviados há quase 20 anos. Eu não usaria esse exemplo em lugar algum.

    
por 20.12.2010 / 17:54
fonte
1

Eu não acho que o operador ternário seja mau.

Aqui está uma pegadinha que me deixou perplexa. Eu era um programador de C para muitos (10 +) e no final dos anos 1990 eu mudei para a programação de aplicativos baseados na web. Como programador web, logo corri em PHP que também tem um operador ternário. Eu tive um bug em um programa PHP que finalmente tracei em uma linha de código com um operador ternário aninhado. Acontece que o operador ternário do PHP associou-se da esquerda para a direita, mas o operador ternário C (ao qual eu estava acostumado) se associa da direita para a esquerda.

    
por 20.12.2010 / 18:47
fonte
1

Qualquer coisa que torne o seu código mais feio é o mal.

Se você usar o ternário para tornar seu código mais limpo, então use-o. Às vezes, em como php, é ótimo fazer substituições em linha, por exemplo

"Hello ".($Male?"Mr":"Ms")." $Name

Isso economiza algumas linhas, e fica bastante claro, mas seu exemplo precisa de formatação pelo menos melhor para ser claro, e ternário não é bom para multilinha, então você pode usar também if / else.

    
por 21.12.2010 / 03:38
fonte
1

Posso dizer isso? Não consigo encontrar essa aplicação específica da operação ternária evil :

  1. a operação que realiza é bem trivial, e uma vez que você tenha passado, dificilmente alguns bugs aparecerão;
  2. o que isso faz é claramente indicado no nome da função;
  3. tomando > 1 linha para algo tão óbvio e que tão claramente não seria melhorado no futuro (a menos que um algoritmo mediano mágico tenha vivido sem ser detectado até agora).

Por favor, tenha misericórdia, minha reputação já é bastante lamentável.

    
por 21.12.2010 / 16:04
fonte
1

Maior vitória: mostrando que existe um único alvo de ação.

if ( $is_whatever )
    $foo = 'A';
else
    $foo = 'B';

Existem dois caminhos de código que você pode seguir, e o leitor deve ler atentamente para ver quais duas variáveis estão sendo definidas. Nesse caso, é apenas uma variável, mas o leitor precisa ler mais para descobrir isso. Afinal, poderia ter sido isso:

if ( $is_whatever )
    $foo = 'A';
else
    $bar = 'B';

Com o operador ternário, fica claro que apenas uma variável está sendo definida.

$foo = $is_whatever ? 'A' : 'B';

No nível mais baixo, é o princípio DRY (Don't Repeat Yourself) no seu nível mais básico. Se você puder especificar $foo apenas uma vez, faça isso.

    
por 26.11.2012 / 16:46
fonte
0

Se ... então ... outra pessoa tende a enfatizar a condição e, portanto, não enfatiza as operações sendo condicionalmente feitas.

o operador ternário é o oposto, ele tende a esconder a condição e, portanto, é útil quando a operação que está sendo executada é mais importante do que a própria condição.

Existe uma ligeira contrariedade técnica, em alguns idiomas, que eles não são muito intercambiáveis devido a um ser uma declaração e um uma expressão, por exemplo inicializando condicionalmente consts em C ++

    
por 20.12.2010 / 17:58
fonte
0

When is appropriate, and when is it not?

Eu acho que quando se está desenvolvendo para um grupo homogêneo de pessoas, não há problema, mas quando você tem que lidar com pessoas que lidam com diferentes níveis, esse tipo de coisa só introduz um nível adicional de complexidade no código. Assim, minha política sobre o assunto é: código claro e não explique em vez de codificar curto e explicar 123123 vezes.

Should it be taught to or hidden from beginners?

Eu não deveria ser ensinado aos iniciantes, preferiria que eles descobrissem quando a necessidade emergisse, então ele só será usado quando necessário e não toda vez que você precisar de um.

    
por 20.12.2010 / 23:25
fonte
0

IMO, o operador em si não é mau, mas a sintaxe usada em C (e C ++) é excessivamente concisa. IMO, Algol 60 fez melhor, então algo assim:

A = x == y ? B : C;

ficaria mais parecido com isso (mas mantendo a sintaxe semelhante a C em geral):

A = if (x==y) B else C;

Mesmo com isso, o aninhamento excessivamente profundo pode levar a problemas de legibilidade, mas pelo menos A) qualquer um que tenha feito programação pode descobrir um simples, e B) pessoas que entendem isso podem lidar com aninhamentos consideravelmente mais profundos . OTOH, eu também notaria que no LISP (por exemplo) um cond é muito parecido com uma declaração ternária - não um conjunto de declarações, mas uma única expressão gera um valor (então, novamente, a maior parte do LISP é como que ...)

    
por 25.01.2011 / 21:12
fonte
0

Uma loja que regularmente escreve métodos de 600 a 1200 linhas não deve dizer-me que um ternário é "difícil de entender". Qualquer loja que regularmente permite que cinco condições avaliem uma ramificação de código não deve me dizer que as condições concretamente resumidas em um ternário são "difíceis de ler".

    
por 11.03.2011 / 17:13
fonte
0

Quando é?: apropriado e quando não é?

  • Se você não obtiver um ganho de desempenho, não o use; isso afeta a legibilidade do seu código.
  • Use uma vez e não aninhe.
  • É mais difícil de depurar.

Deve ser ensinado ou escondido de iniciantes?

Não importa, mas não deve ser intencionalmente escondido, pois não é muito complexo para um iniciante aprender.

    
por 23.09.2015 / 22:11
fonte
-2

No seu exemplo:

def median(a, b, c):
    if a < b < c: return b
    if a < c < b: return c
    if b < a < c: return a
    if b < c < a: return c
    if c < a < b: return a
    if c < b < a: return b

é muito simples de ler e óbvio. A variável entre os < < é o valor de retorno.

Atualizar

mesmo, mas menos linhas de código. Ainda simples, eu acho.

def median(a, b, c):
    if b<a<c or c<a<b: return a
    if a<b<c or c<b<a: return b
    if a<c<b or b<c<a: return c
    
por 26.01.2011 / 01:50
fonte
-2

Também é necessário para const

const int nLegs  = isChicken ? 2: 4 ;
    
por 11.03.2011 / 17:40
fonte