Ternário ou não ternário? [fechadas]

186

Pessoalmente, sou advogado do operador ternário: ()? :; Eu percebo que ele tem o seu lugar, mas me deparei com muitos programadores que são totalmente contra o uso, e alguns que o usam com muita frequência.

Quais são seus sentimentos sobre isso? Que código interessante você já viu usando?

pixel
fonte
22
Um defensor de alguma coisa é uma pessoa que apóia essa coisa.
Doug McClean
8
Use-o quando estiver claro, evite-o quando estiver confuso. Essa é uma decisão de julgamento. Pode tornar o código mais legível, mas apenas para expressões simples. Tentar sempre usá-lo é uma ameaça, tanto quanto evitá-lo incansavelmente.
Abel
3
Na verdade, é o operador condicional. Uma pergunta quase duplicada é stackoverflow.com/questions/725973/… .
Daniel Daranas
Eu estava usando às vezes x = x if x else y, mas, em seguida, perguntou sobre isso e percebi com os outros ajuda que ele realmente só reduz para x = x ou y ( stackoverflow.com/questions/18199381/self-referencing-ternary/... )
desalinhado
4
Perguntas como essas não devem ser consideradas não construtivas.
Ungeheuer

Respostas:

243

Use-o apenas para expressões simples :

int a = (b > 10) ? c : d;

Não encadeie ou aninhe operadores ternários, pois é difícil de ler e confuso:

int a = b > 10 ? c < 20 ? 50 : 80 : e == 2 ? 4 : 8;

Além disso, ao usar o operador ternário, considere formatar o código de uma maneira que melhore a legibilidade:

int a = (b > 10) ? some_value                 
                 : another_value;
marcospereira
fonte
80
Concordo totalmente com as primeiras afirmações, mas discordo totalmente do seu exemplo de "melhor legibilidade". Se você está procurando por várias linhas, por que não usar apenas uma instrução if?
9788 Joe Phillips #
3
só porque se else é muito mais detalhado para decisões simples: int a = 0; if (b> 10) a = algum valor; mais a = outro_valor; O que você prefere?
Marcospereira 05/10/09
44
@ d03boy: Porque a declaração if é apenas isso, uma declaração e não serve quando tudo o que você quer é uma expressão.
falstro
2
@roe em algumas línguas se é expressão (por exemplo, no Scala), por isso val x = if(true) 0 else 1é perfeitamente legal
om-nom-nom
5
@ om-nom-nom caso em questão, isso tornaria uma expressão if, em vez de uma declaração if, e é essencialmente a mesma coisa que o operador?: -.
falstro 07/12/12
140

Isso torna a depuração um pouco mais difícil, pois você não pode colocar pontos de interrupção em cada uma das subexpressões. Eu uso raramente.

David Segonds
fonte
44
Esse é o melhor argumento contra o operador ternário que eu já ouvi. Eu não compro o argumento "não legível" (parece-me que as pessoas estão com preguiça de se acostumar), mas isso realmente tem substância.
EpsilonVector
80

Eu os amo, especialmente em idiomas seguros para tipos.

Não vejo como isso:

int count = (condition) ? 1 : 0;

é mais difícil do que isso:

int count;

if (condition)
{
  count = 1;
} 
else
{
  count = 0;
}

editar -

Eu argumentaria que os operadores ternários tornam tudo menos complexo e mais elegante do que a alternativa.

Ian P
fonte
5
A inicialização ternária é ainda mais útil em D ou C ++ quando a variável é constante. por exemplo const int count = ...;
deft_code 15/02/11
Bem, você está meio que deturpando if/elseos aparelhos desnecessários de lá.
bobobobo
1
Além disso, neste caso, se conditioné bool que você poderia apenas fazer int count = condition;
bobobobo
1
@bobobobo esta if/elsecom suspensórios é como a maioria dos programadores irá reescrever o ternário ..
Andre Figueiredo
1
@bobobobo se / else sem aparelhos estiver apenas pedindo problemas. É muito fácil para alguém adicionar uma linha, mas esqueça que ele precisará de chaves para fazer o que espera (execute a linha adicional como parte de um bloco): stackoverflow.com/a/381274/377225
George Marian
43

Acorrentado, estou bem - aninhado, nem tanto.

Eu costumo usá-los mais em C simplesmente porque eles são uma instrução if que tem valor, por isso diminui a repetição ou variáveis ​​desnecessárias:

x = (y < 100) ? "dog" :
    (y < 150) ? "cat" :
    (y < 300) ? "bar" : "baz";

ao invés de

     if (y < 100) { x = "dog"; } 
else if (y < 150) { x = "cat"; }
else if (y < 300) { x = "bar"; } 
else              { x = "baz"; }

Em tarefas como essa, acho que é menos refatorar e mais claro.

Por outro lado, quando estou trabalhando em rubi, é mais provável que eu use, if...else...endporque também é uma expressão.

x =   if (y < 100) then "dog"
    elif (y < 150) then "cat"
    elif (y < 300) then "bar"
    else                "baz"
    end

(embora, reconhecidamente, para algo tão simples, eu possa usar o operador ternário de qualquer maneira).

rampion
fonte
2
Gosto do seu primeiro exemplo - nunca pensei em encaderná-los dessa maneira antes. Obrigado por compartilhar. =)
Erik Forbes
5
+1 Recentemente, comecei a fazer isso. Na verdade, até faço isso para substituir as instruções do switch.
Davy8
1
Excelente exemplo @rampion.
ylluminate
39

O ?:operador ternário é apenas um equivalente funcional da ifconstrução processual . Portanto, desde que você não esteja usando ?:expressões aninhadas , os argumentos a favor / contra a representação funcional de qualquer operação se aplicam aqui. Porém, o aninhamento de operações ternárias pode resultar em um código totalmente confuso (exercício para o leitor: tente escrever um analisador que lide com condicionais ternários aninhados e você apreciará sua complexidade).

Mas há muitas situações em que o uso conservador do ?:operador pode resultar em código que é realmente mais fácil de ler do que o contrário. Por exemplo:

int compareTo(Object object) {
    if((isLessThan(object) && reverseOrder) || (isGreaterThan(object) && !reverseOrder)) {
       return 1;
    if((isLessThan(object) && !reverseOrder) || (isGreaterThan(object) && reverseOrder)) {
       return -1;
    else
      return 0;              
}

Agora compare isso com isso:

int compareTo(Object object) {
    if(isLessThan(object))
        return reverseOrder ? 1 : -1;         
    else(isGreaterThan(object))
        return reverseOrder ? -1 : 1;
    else        
       return 0;              
}

Como o código é mais compacto, há menos ruído sintático e, usando criteriosamente o operador ternário (isso é apenas em relação à propriedade reverseOrder ), o resultado final não é particularmente conciso.

Ryan Delucchi
fonte
eu ainda defenderia o uso de elogios em todas as construções if / then / else que não sejam ternárias, portanto seu segundo exemplo está faltando alguns exemplos.
Kris
Sim, é funcional. É como uma função pequena que tem um único argumento boolean e, retorna qualquer tipo que você quiser! Na verdade, um operador limpo.
22412 bobobobo
24

É uma questão de estilo, realmente; as regras subconscientes que eu costumo seguir são:

  • Avalie apenas 1 expressão - então foo = (bar > baz) ? true : false, mas NÃOfoo = (bar > baz && lotto && someArray.Contains(someValue)) ? true : false
  • Se eu o estiver usando para lógica de exibição, por exemplo <%= (foo) ? "Yes" : "No" %>
  • Apenas use-o realmente para atribuição; nunca flui lógica (então nunca (foo) ? FooIsTrue(foo) : FooIsALie(foo)) A lógica do fluxo no ternário é em si uma mentira, ignore esse último ponto.

Gosto porque é conciso e elegante para operações de atribuição simples.

Keith Williams
fonte
boas orientações e bons exemplos!
nickf
Eu acho que a maioria dos idiomas não permite que você o use para a lógica de fluxo, então você não pode fazer (foo)? True (foo): False (foo); a menos que fosse uma tarefa.
Henry B
Opa, sim, você está certo, meu mal.
Keith Williams
21
Seus dois primeiros exemplos são muito ruins. Os resultados das comparações já são valores booleanos; portanto, seus operadores ternários são inúteis e apenas complicam o código.
8309 Trillian
1
@Trillian +1 Sim, deveria ter escolhido uma tarefa diferente. foo = (bar > baz);é muito mais simples
Eric
18

Como tantas perguntas de opinião, a resposta é inevitavelmente: depende

Para algo como:

return x ? "Yes" : "No";

Eu acho que é muito mais conciso (e mais rápido para eu analisar) do que:

if (x) {
    return "Yes";
} else {
    return "No";
}

Agora, se sua expressão condicional é complexa, a operação ternária não é uma boa escolha. Algo como:

x && y && z >= 10 && s.Length == 0 || !foo

não é um bom candidato para o operador ternário.

Além disso, se você é um programador C, o GCC realmente possui uma extensão que permite excluir a parte se verdadeira do ternário, assim:

/* 'y' is a char * */
const char *x = y ? : "Not set";

Que irá definir xa yassumir ynão é NULL. Coisa boa.

Sean Bright
fonte
Corrigido um leve problema de sintaxe e gramática, Sean :-) Faltando y no último bit de código e "atribuir x a y" significa "y = x", então eu escolhi "definir x como y".
21420
@Pax: Obrigado! Revirei a alteração de sintaxe, pois estava tentando apontar que, com as extensões do GCC, você não precisa da parte se-verdadeira do ternário.
Sean Bright
Desculpe, não vi esse parágrafo. Mas não sei se concordo com esse tipo de coisa, pois permite que as pessoas escrevam código que não será compilado com um compilador padrão ISO. Ainda assim, quando o GCC for o último homem de pé, isso não importará :-) #
1100
É vodu, com certeza ... E quem não usa o GCC? : D
Sean Bright
14

Na minha opinião, só faz sentido usar o operador ternário nos casos em que uma expressão é necessária.

Em outros casos, parece que o operador ternário diminui a clareza.

John Mulder
fonte
o problema é que é de 99% da linguagem, uma expressão pode ser substituída por uma função ... e as pessoas que evitam o operador ternário preferem essa solução.
PierreBdR 01/10/08
11

Pela medida da complexidade ciclomática , o uso de ifinstruções ou o operador ternário são equivalentes. Portanto, por essa medida, a resposta é não , a complexidade seria exatamente a mesma de antes.

Por outras medidas, como legibilidade, capacidade de manutenção e DRY (não se repita), uma das opções pode ser melhor que a outra.

Greg Hewgill
fonte
10

Eu o uso com frequência em locais onde sou obrigado a trabalhar em um construtor - por exemplo, as novas construções .NET 3.5 LINQ to XML - para definir valores padrão quando um parâmetro opcional é nulo.

Exemplo artificial:

var e = new XElement("Something",
    param == null ? new XElement("Value", "Default")
                  : new XElement("Value", param.ToString())
);

ou (obrigado asterita)

var e = new XElement("Something",
    new XElement("Value",
        param == null ? "Default"
                      : param.ToString()
    )
);

Não importa se você usa o operador ternário ou não, é importante garantir que seu código seja legível. Qualquer construção pode ficar ilegível.

Erik Forbes
fonte
Ou ... var e = novo XElement ("Algo", novo XElement ("valor", param == null? "Padrão": param.toString ()));
asterite
2
Eu gosto que você está formatando para facilitar a leitura, muitos não.
Bruceatk 02/10/08
Qual a utilidade do código fonte legível por humanos se não for legível por humanos? =)
Erik Forbes
9

Eu uso o operador ternário sempre que posso, a menos que torne o código extremamente difícil de ler, mas isso geralmente é apenas uma indicação de que meu código poderia usar um pouco de refatoração.

Sempre me intriga como algumas pessoas pensam que o operador ternário é um recurso "oculto" ou um tanto misterioso. É uma das primeiras coisas que aprendi quando começo a programar em C e não acho que diminua a legibilidade. É uma parte natural da linguagem.

ilitirit
fonte
1
Estou completamente de acordo. Não há nada oculto ou complicado nisso.
mmattax 02/10/08
2
Isso pode causar problemas de legibilidade, especialmente quando aninhados.
David Thornley
Eu acho que " extremamente difícil de ler" é um pouco permissivo, mas no geral eu concordo com você. Não há nada de difícil ou místico nisso.
EpsilonVector
8

(Hack do dia)

#define IF(x) x ?
#define ELSE :

Então você pode fazer if-then-else como expressão:

int b = IF(condition1)    res1
        ELSE IF(condition2)  res2
        ELSE IF(conditions3) res3
        ELSE res4;
John John
fonte
7

Concordo com jmulder: não deve ser usado no lugar de a if, mas tem seu lugar para expressão de retorno ou dentro de uma expressão:

echo "Result: " + n + " meter" + (n != 1 ? "s" : "");
return a == null ? "null" : a;

O primeiro é apenas um exemplo, um melhor suporte i18n ao plural deve ser usado!

PhiLho
fonte
O primeiro ternário está incorreto - você tem um: onde o? deve ir: (n! = 1 ? "s": "")
Erik Forbes
Sim, obrigado por apontar isso! Fixo.
PhiLho
6

Se você estiver usando o operador ternário para uma atribuição condicional simples, acho que está bem. Eu já vi (ab) usado para controlar o fluxo do programa sem nem mesmo fazer uma atribuição, e acho que isso deve ser evitado. Use uma instrução if nesses casos.

Bill the Lizard
fonte
5

Eu acho que o operador ternário deve ser usado quando necessário. Obviamente, é uma escolha muito subjetiva, mas acho que uma expressão simples (especialmente como expressão de retorno) é muito mais clara que um teste completo. Exemplo em C / C ++:

return (a>0)?a:0;

Comparado com:

if(a>0) return a;
else return 0;

Você também tem o caso em que a solução está entre o operador ternário e a criação de uma função. Por exemplo, em Python:

l = [ i if i > 0 else 0 for i in lst ]

A alternativa é:

def cap(value):
    if value > 0:
        return value
    return 0
l = [ cap(i) for i in lst ]

É necessário o suficiente para que, em Python (como exemplo), esse idioma possa ser visto regularmente:

l = [ ((i>0 and [i]) or [0])[0] for i in lst ]

esta linha usa propriedades dos operadores lógicos no Python: eles são preguiçosos e retornam o último valor calculado se for igual ao estado final.

PierreBdR
fonte
3
Essa última linha dói meu cérebro ...
Erik Forbes
5

Eu gosto deles. Não sei por que, mas me sinto bem quando uso a expressão ternária.

JimDaniel
fonte
5

Eu já vi bestas assim (na verdade, era muito pior, pois era isValidDate e checava mês e dia também, mas não me incomodei em tentar lembrar a coisa toda):

isLeapYear =
    ((yyyy % 400) == 0)
    ? 1
    : ((yyyy % 100) == 0)
        ? 0
        : ((yyyy % 4) == 0)
            ? 1
            : 0;

onde, claramente, uma série de declarações if seria melhor (embora essa ainda seja melhor do que a versão macro que vi uma vez).

Não me importo com coisas pequenas como:

reportedAge = (isFemale && (Age >= 21)) ? 21 + (Age - 21) / 3 : Age;

ou até coisas um pouco complicadas, como:

printf ("Deleted %d file%s\n", n, (n == 1) ? "" : "s");
paxdiablo
fonte
Como você pode dizer uma série de isolando se as instruções seriam mais legíveis? Eu li sua "besta" muito bem . reportedAgeé o exemplo que leva algum alguns figurando - provavelmente porque é mais um caso particular do que descobririsThisYearALeapYear
Axeman
4

Bem, a sintaxe para isso é horrível. Acho ifs funcionais muito úteis e geralmente torna o código mais legível.

Sugiro criar uma macro para torná-la mais legível, mas tenho certeza de que alguém pode apresentar um caso de borda horrível (como sempre existe no CPP).

Marcin
fonte
muitas implementações e variantes BASIC têm uma função SE que substitui o operador ternário. Eu vi um número de bases de código com que definiram como uma macro em C.
Sparr
Bem, eu estava pensando em linguagens de programação funcionais, mas sim.
Marcin
"Fazendo uma macro para torná-la mais legível", você é muito brincalhão!
NiXar
4

Eu gosto de usar o operador no código de depuração para imprimir valores de erro, para que eu não precise procurá-los o tempo todo. Normalmente, faço isso para impressões de depuração que não permanecerão quando terminar o desenvolvimento.

int result = do_something();
if( result != 0 )
{
  debug_printf("Error while doing something, code %x (%s)\n", result,
                result == 7 ? "ERROR_YES" :
                result == 8 ? "ERROR_NO" :
                result == 9 ? "ERROR_FILE_NOT_FOUND" :
                "Unknown");
}
indiv
fonte
4

Eu quase nunca uso o operador ternário, porque sempre que eu o uso, isso sempre me faz pensar muito mais do que preciso depois, quando tento mantê-lo.

Eu gosto de evitar a verbosidade, mas quando tornar o código muito mais fácil de entender, irei pela verbosidade.

Considerar:

String name = firstName;

if (middleName != null) {
    name += " " + middleName;
}

name += " " + lastName;

Agora, isso é um pouco detalhado, mas acho muito mais legível do que:

String name = firstName + (middleName == null ? "" : " " + middleName)
    + " " + lastName;

ou:

String name = firstName;
name += (middleName == null ? "" : " " + middleName);
name += " " + lastName;

Parece apenas compactar informações demais em pouco espaço, sem deixar claro o que está acontecendo. Toda vez que vejo o operador ternário sendo usado, sempre encontro uma alternativa que parecia muito mais fácil de ler ... então, essa é uma opinião extremamente subjetiva. Portanto, se você e seus colegas acham o ternário muito legível, siga em frente.

Mike Stone
fonte
1
Mas isso não é exatamente a mesma coisa. No segundo exemplo, você está compactando todas as três instruções em uma linha. É isso que diminui a legibilidade, não o operador ternário.
Ilitirit 01/10/08
É justo, atualizei para incorporar seu comentário, mas ele ainda parece confuso para mim ... mas, novamente, é subjetivo ... Não estou dizendo que ternário não é legível, estou dizendo que não é legível para mim (99 % do tempo)
Mike Stone
3

Apenas quando:

$ var = (simples> teste? simples_result_1: simples_result_2);

BEIJO.

Jared Farrish
fonte
3

Eu normalmente uso em coisas como esta:

before:

if(isheader)
    drawtext(x,y,WHITE,string);
else
    drawtext(x,y,BLUE,string);

after:

    drawtext(x,y,isheader==true?WHITE:BLUE,string);
KPexEA
fonte
Obviamente, na maioria dos idiomas, você também não precisaria da parte "== true" desse ternário.
Michael Haren
Eu percebo que, embora eu tendem a colocá-lo em apenas para tornar o código mais legível desde o compilador deve otimizá-lo para a mesma coisa que sem a == true de qualquer maneira
KPexEA
em qualquer linguagem que possam precisar "== true"
Nixar
Tive dificuldades para decidir se votaria ou não. O exemplo é bom, mas o == TRUE é algo que eu não suporto ver no código de outras pessoas.
Peter Perháč
3

Como outros já apontaram, eles são bons para condições curtas e simples. Eu gosto especialmente deles por padrão (como o || e / ou uso em javascript e python), por exemplo

int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;

Outro uso comum é inicializar uma referência em C ++. Como as referências precisam ser declaradas e inicializadas na mesma instrução, você não pode usar uma instrução if.

SomeType& ref = pInput ? *pInput : somethingElse;
Maccullt
fonte
2
Surpreendente que esta seja a primeira menção de referências de inicialização, que é um dos poucos lugares em que "se" não pode ser usado em vez de?:. (Acho que porque essa não é uma pergunta específica para C ++ ...) Eles também são úteis nas listas de inicialização de construtores, pelo mesmo motivo.
j_random_hacker
2

Trato os operadores ternários muito como o GOTO. Eles têm o seu lugar, mas são algo que você normalmente deve evitar para facilitar a compreensão do código.

Dan Walker
fonte
2

Recentemente, vi uma variação nos operadores ternários (bem, mais ou menos) que fazem a variante padrão "()?:" Parecer um exemplo de clareza:

var Result = [CaseIfFalse, CaseIfTrue][(boolean expression)]

ou, para dar um exemplo mais tangível:

var Name = ['Jane', 'John'][Gender == 'm'];

Lembre-se, isso é Javascript, então coisas assim podem não ser possíveis em outros idiomas (felizmente).

pilsetnieks
fonte
1
uau, isso é horrível! imagine aninhar alguns deles juntos! A única coisa vagamente útil que posso ver com isso é se você tivesse uma função que retornasse uma matriz de 2 elementos: var Name = getNames () [Gender == 'm']; ... mas isso é MENOR legível!
nickf
2

Para casos simples, eu gosto de usá-lo. Na verdade, é muito mais fácil ler / codificar, por exemplo, como parâmetros para funções ou coisas assim. Também para evitar a nova linha, eu gosto de manter todos os meus if / else.

Neseting seria um grande NÃO-NÃO no meu livro.

Então, resumindo, por um único if / else, usarei o operador ternário. Para outros casos, um if / else if / else regular (ou alternar)

Rodrigo Gómez
fonte
2

Gosto do caso especial de Groovy do operador ternário, chamado de operador Elvis:?:

expr ?: default

Esse código avalia expr se não for nulo e, se for o padrão. Tecnicamente, não é realmente um operador ternário, mas definitivamente está relacionado a ele e economiza muito tempo / digitação.

Steve Losh
fonte
Sim, eu amo isso bem - é ??em C #, o operador nulo coalesce: stackoverflow.com/questions/278703/...
Jarrod Dixon
2

Para tarefas simples, como atribuir um valor diferente, dependendo de uma condição, elas são ótimas. Eu não os usaria quando houver expressões mais longas, dependendo da condição.

Svet
fonte
2

Tantas respostas disseram, depende . Acho que se a comparação ternária não estiver visível em uma verificação rápida do código, ela não deverá ser usada.

Como uma questão secundária, eu também posso observar que sua própria existência é realmente um pouco anômala, devido ao fato de que em C, o teste de comparação é uma afirmação. No Icon, a ifconstrução (como a maioria do Icon) é na verdade uma expressão. Então você pode fazer coisas como:

x[if y > 5 then 5 else y] := "Y" 

... que eu acho muito mais legível do que um operador de comparação intermediário. :-)

Recentemente, houve uma discussão sobre a possibilidade de adicionar o ?:operador ao Icon, mas várias pessoas apontaram corretamente que não havia absolutamente nenhuma necessidade devido à maneira comoif funciona.

O que significa que se você pudesse fazer isso em C (ou em qualquer outro idioma que possua o operador ternery), não precisaria, de fato, do operador ternery.

staticsan
fonte
2

Se você e seus colegas de trabalho entendem o que fazem e não são criados em grandes grupos, acho que eles tornam o código menos complexo e mais fácil de ler, porque simplesmente há menos código.

A única vez que acho que os operadores ternários dificultam o entendimento do código é quando você tem mais de 3 ou 4 em uma linha. A maioria das pessoas não se lembra de que elas têm precedência correta e quando você tem uma pilha delas, a leitura do código é um pesadelo.

Alex
fonte