¿Ternario o no ternario? [cerrado]

186

Personalmente, soy un defensor del operador ternario: ()? :; Me doy cuenta de que tiene su lugar, pero me he encontrado con muchos programadores que están completamente en contra de usarlo, y algunos que lo usan con demasiada frecuencia.

¿Qué sientes al respecto? ¿Qué código interesante has visto usándolo?

píxeles
fuente
22
Un defensor de algo es una persona que apoya esa cosa.
Doug McClean
8
Úselo cuando esté claro, evítelo cuando confunda. Esa es una decisión judicial. Puede hacer que el código sea más legible, pero solo para expresiones simples. Intentar usarlo siempre es tanto una amenaza como evitarlo sin descanso.
Abel el
3
En realidad, es el operador condicional. Una pregunta cercana a la duplicada es stackoverflow.com/questions/725973/… .
Daniel Daranas
A veces usaba, x = x if x else ypero luego pregunté al respecto y me di cuenta con la ayuda de otros que realmente solo se reduce a x = x o y ( stackoverflow.com/questions/18199381/self-referencing-ternary/… )
Scruffy
44
Preguntas como estas no deben considerarse no constructivas.
Ungeheuer

Respuestas:

243

Úselo solo para expresiones simples :

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

No encadene ni anide operadores ternarios ya que es difícil de leer y confuso:

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

Además, cuando use un operador ternario, considere formatear el código de una manera que mejore la legibilidad:

int a = (b > 10) ? some_value                 
                 : another_value;
marcospereira
fuente
81
Totalmente de acuerdo con las primeras declaraciones, pero totalmente en desacuerdo con su ejemplo de "legibilidad mejorada". Si opta por varias líneas, ¿por qué no usar una declaración if?
Joe Phillips el
3
solo porque, si no, es bastante más detallado para decisiones simples: int a = 0; if (b> 10) a = some_value; sino a = otro_valor; ¿Qué prefieres?
marcospereira 05 de
44
@ d03boy: Porque la declaración if es solo eso, una declaración, y no funcionará cuando todo lo que quieres es una expresión.
falstro
2
@roe en algunos idiomas si es la expresión (por ejemplo, en Scala), por lo que val x = if(true) 0 else 1es perfectamente legal
om-nom-nom
55
El caso de @ om-nom-nom en el punto, eso lo convertiría en una expresión if, en lugar de una declaración if, y es esencialmente lo mismo que el operador?: -.
falstro
141

Hace que la depuración sea un poco más difícil ya que no puede colocar puntos de interrupción en cada una de las subexpresiones. Lo uso raramente.

revs David Segonds
fuente
44
Ese es el mejor argumento contra el operador ternario que he escuchado. No compro el argumento de "no legible" (me parece que la gente es demasiado perezosa para acostumbrarse), pero en realidad esto tiene sustancia.
EpsilonVector
80

Los amo, especialmente en lenguajes de tipo seguro.

No veo cómo esto:

int count = (condition) ? 1 : 0;

es más difícil que esto:

int count;

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

editar -

Yo diría que los operadores ternarios hacen que todo sea menos complejo y más ordenado que la alternativa.

Ian P
fuente
55
La inicialización ternaria es aún más útil en D o C ++ cuando la variable es constante. por ejemplo const int count = ...;
deft_code
Bueno, estás tergiversando if/elselas llaves innecesarias allí.
bobobobo
1
También, en este caso si conditiones bool que sólo se podía hacer int count = condition;
bobobobo
1
@bobobobo esto if/elsecon llaves es cómo la mayoría de los programadores reescribirán el ternario ..
Andre Figueiredo
1
@bobobobo if / else w / o braces solo está pidiendo problemas. Es demasiado fácil para alguien agregar una línea, pero olvide que necesitará llaves para hacer lo que espera (ejecute la línea adicional como parte de un bloque): stackoverflow.com/a/381274/377225
George Marian
43

Estoy bien encadenado, anidado, no tanto.

Tiendo a usarlos más en C simplemente b / c son una declaración if que tiene valor, por lo que reduce la repetición o las variables innecesarias:

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

más bien que

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

En tareas como esta, encuentro que es menos refactorizante, y más claro.

Por otro lado, cuando trabajo en rubí, es más probable que lo use if...else...endporque también es una expresión.

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

(aunque, es cierto, para algo tan simple, podría usar el operador ternario de todos modos).

rampion
fuente
2
Me gusta tu primer ejemplo, no había pensado encadenarlos así antes. Gracias por compartir. =)
Erik Forbes
55
+1 De hecho, recientemente comencé a hacer eso. Incluso lo hago para reemplazar las declaraciones de cambio.
Davy8
1
Excelente ejemplo @rampion.
iluminar
39

El ?:operador ternario es simplemente un equivalente funcional del ifconstructo procesal . Por lo tanto, siempre que no esté utilizando ?:expresiones anidadas , los argumentos a favor / en contra de la representación funcional de cualquier operación se aplican aquí. Pero las operaciones ternarias de anidamiento pueden dar como resultado un código francamente confuso (ejercicio para el lector: intente escribir un analizador que maneje condicionales ternarios anidados y apreciará su complejidad).

Pero hay muchas situaciones en las que el uso conservador del ?:operador puede dar como resultado un código que en realidad es más fácil de leer que de lo contrario. Por ejemplo:

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;              
}

Ahora compara eso con esto:

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

Como el código es más compacto, hay menos ruido sintáctico, y al usar el operador ternario con prudencia (eso es solo en relación con la propiedad reverseOrder ) el resultado final no es particularmente breve.

Ryan Delucchi
fuente
Todavía recomendaría el uso de elogios en cada construcción if / then / else que no sea tan ternaria, por lo que a su segundo ejemplo le faltan algunos.
Kris
Sí, es funcional. Es como una pequeña función que tiene un único argumento booleano y devuelve cualquier tipo que desee. En realidad, un operador ordenado.
bobobobo
24

Es una cuestión de estilo, de verdad; Las reglas subconscientes que tiendo a seguir son:

  • Solo evalúa 1 expresión, entonces foo = (bar > baz) ? true : false, pero NOfoo = (bar > baz && lotto && someArray.Contains(someValue)) ? true : false
  • Si lo estoy usando para la lógica de visualización, por ejemplo <%= (foo) ? "Yes" : "No" %>
  • Solo lo utilizo realmente para la asignación; nunca fluya la lógica (así que nunca (foo) ? FooIsTrue(foo) : FooIsALie(foo)) La lógica de flujo en ternario es en sí misma una mentira, ignore ese último punto.

Me gusta porque es conciso y elegante para operaciones de asignación simples.

Keith Williams
fuente
buenas pautas y buenos ejemplos!
nickf
Creo que la mayoría de los idiomas no te permiten usarlo para la lógica de flujo, por lo que no podrías hacer (foo) Verdadero (foo): Falso (foo); a menos que fuera una tarea.
Henry B
Vaya, sí, tienes razón, mi mal.
Keith Williams el
21
Tus dos primeros ejemplos son realmente malos. Los resultados de las comparaciones ya son valores booleanos, por lo que sus operadores ternarios son inútiles y solo complican el código.
Trillian
1
@Trillian +1 Sí, debería haber ido con una tarea diferente. foo = (bar > baz);es mucho más simple
Eric
18

Como muchas preguntas de opinión, la respuesta es inevitable: depende

Por algo como:

return x ? "Yes" : "No";

Creo que es mucho más conciso (y más rápido para analizar) que:

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

Ahora, si su expresión condicional es compleja, entonces la operación ternaria no es una buena opción. Algo como:

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

no es un buen candidato para el operador ternario.

Por otro lado, si usted es un programador en C, GCC en realidad tiene una extensión que le permite excluir la parte de verdadero del ternario, como esta:

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

Que establecerá xa yasumir yque no es NULL. Buen material.

Sean Bright
fuente
Se corrigió un pequeño problema de sintaxis y gramática, Sean :-) Falta y del último bit de código y "asignar x a y" significa "y = x", así que cambié a "establecer x a y".
paxdiablo
@Pax: ¡Gracias! Revertí el cambio de sintaxis ya que estaba tratando de señalar que con las extensiones de GCC no necesitas la porción verdadera del ternario.
Sean Bright
Lo siento, no vi ese párrafo. Sin embargo, no sé si estoy de acuerdo con ese tipo de cosas, ya que permite a las personas escribir código que no se compilará con un compilador estándar ISO. Aún así, cuando GCC es el último hombre en pie, eso no importará :-)
paxdiablo
Es vudú, seguro ... ¿Y quién no usa GCC? : D
Sean Bright
14

En mi opinión, solo tiene sentido usar el operador ternario en los casos en que se necesita una expresión.

En otros casos, parece que el operador ternario disminuye la claridad.

John Mulder
fuente
El problema es que es el 99% del lenguaje, una expresión puede ser reemplazada por una función ... y ppl evitando el operador ternario incluso preferirá esa solución.
PierreBdR
11

Por la medida de la complejidad ciclomática , el uso de ifdeclaraciones o el operador ternario son equivalentes. Entonces, según esa medida, la respuesta es no , la complejidad sería exactamente la misma que antes.

Según otras medidas, como la legibilidad, la capacidad de mantenimiento y DRY (no repetir), cualquiera de las opciones puede ser mejor que la otra.

Greg Hewgill
fuente
10

Lo uso con bastante frecuencia en lugares donde estoy obligado a trabajar en un constructor, por ejemplo, las nuevas construcciones .NET 3.5 LINQ to XML, para definir valores predeterminados cuando un parámetro opcional es nulo.

Ejemplo contribuido:

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

o (gracias asterita)

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

No importa si usa el operador ternario o no, lo importante es asegurarse de que su código sea legible. Cualquier construcción puede hacerse ilegible.

Erik Forbes
fuente
O ... var e = new XElement ("Something", new XElement ("value", param == null? "Default": param.toString ()));
asterita el
2
Me gusta que lo esté formateando para facilitar su lectura, muchos no lo hacen.
bruceatk
¿De qué sirve el código fuente legible por humanos si no es legible por humanos? =)
Erik Forbes
9

Uso el operador ternario siempre que puedo, a menos que haga que el código sea extremadamente difícil de leer, pero eso suele ser solo una indicación de que mi código podría usar un poco de refactorización.

Siempre me sorprende cómo algunas personas piensan que el operador ternario es una característica "oculta" o algo misteriosa. Es una de las primeras cosas que aprendí cuando comienzo a programar en C, y no creo que disminuya en absoluto la legibilidad. Es una parte natural del lenguaje.

ilitirit
fuente
1
Estoy completamente de acuerdo. No hay nada oculto o complicado al respecto.
mmattax
2
Puede causar problemas de legibilidad, especialmente cuando está anidado.
David Thornley el
Creo que " extremadamente difícil de leer" es demasiado permisivo, pero en general estoy de acuerdo con usted. No hay nada difícil o místico al respecto.
EpsilonVector
7

Estoy de acuerdo con jmulder: no debe usarse en lugar de a if, pero tiene su lugar para la expresión de retorno o dentro de una expresión:

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

El primero es solo un ejemplo, ¡se debería usar un mejor soporte de i18n en plural!

PhiLho
fuente
El primer ternario es incorrecto. Tienes un: ¿dónde? debería ir: (n! = 1 ? "s": "")
Erik Forbes
Sí, gracias por señalar eso. Fijo.
PhiLho
7

(Hack del día)

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

Entonces puedes hacer if-then-else como expresión:

int b = IF(condition1)    res1
        ELSE IF(condition2)  res2
        ELSE IF(conditions3) res3
        ELSE res4;
John John
fuente
esto no responde la pregunta
Bruno Alexandre Rosa
6

Si está utilizando el operador ternario para una asignación condicional simple, creo que está bien. Lo he visto (ab) usado para controlar el flujo del programa sin siquiera hacer una asignación, y creo que debería evitarse. Use una declaración if en estos casos.

Bill el lagarto
fuente
5

Creo que el operador ternario debería usarse cuando sea necesario. Obviamente es una elección muy subjetiva, pero encuentro que una expresión simple (especialmente como expresión de retorno) es mucho más clara que una prueba completa. Ejemplo en C / C ++:

return (a>0)?a:0;

Comparado con:

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

También tiene el caso donde la solución es entre el operador ternario y la creación de una función. Por ejemplo en Python:

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

La alternativa es:

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

Se necesita lo suficiente como para que en Python (como ejemplo), tal lenguaje se pueda ver regularmente:

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

Esta línea utiliza las propiedades de los operadores lógicos en Python: son vagos y devuelve el último valor calculado si es igual al estado final.

PierreBdR
fuente
3
Esa última línea me duele el cerebro ...
Erik Forbes
5

Me gustan No sé por qué, pero me siento muy bien cuando uso la expresión ternaria.

JimDaniel
fuente
5

He visto tales bestias como (en realidad fue mucho peor ya que era ValidDate y también se verificó mes y día, pero no me molesté en tratar de recordar todo):

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

donde, claramente, una serie de sentencias if hubiera sido mejor (aunque esta sigue siendo mejor que la versión macro que vi una vez).

No me importa para cosas pequeñas como:

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

o incluso cosas un poco difíciles como:

printf ("Deleted %d file%s\n", n, (n == 1) ? "" : "s");
paxdiablo
fuente
¿Cómo puedes decir una serie de aislamientos si las declaraciones serían más legibles? Leí tu "bestia" muy bien . reportedAgees el ejemplo que requiere un poco de desciframiento, probablemente porque es más un caso particular que descifrarloisThisYearALeapYear
Axeman
4

Bueno, la sintaxis es horrible. Encuentro funcional ifs muy útil, y a menudo hace que el código sea más legible.

Sugeriría hacer una macro para que sea más legible, pero estoy seguro de que alguien puede llegar a un caso extremo horrible (como siempre ocurre con CPP).

Marcin
fuente
Muchas implementaciones y variantes BÁSICAS tienen una función IF que toma el lugar del operador ternario. He visto una serie de bases de código con eso definido como una macro en C.
Sparr
Bueno, estaba pensando en lenguajes de programación funcionales, pero sí.
Marcin
"Hacer una macro para que sea más legible", ¡eres bastante bromista!
niXar
4

Me gusta usar el operador en el código de depuración para imprimir valores de error, así que no tengo que buscarlos todo el tiempo. Por lo general, hago esto para las impresiones de depuración que no van a permanecer una vez que termine de desarrollar.

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
fuente
4

Casi nunca uso el operador ternario porque cada vez que lo uso, siempre me hace pensar mucho más de lo que tengo que pensar cuando trato de mantenerlo.

Me gusta evitar la verbosidad, pero cuando hace que el código sea mucho más fácil de aprender, iré por la verbosidad.

Considerar:

String name = firstName;

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

name += " " + lastName;

Ahora, eso es un poco detallado, pero me parece mucho más legible que:

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

o:

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

Simplemente parece comprimir demasiada información en muy poco espacio, sin dejar en claro lo que está sucediendo. Cada vez que veo que se usa un operador ternario, siempre encuentro una alternativa que parecía mucho más fácil de leer ... una vez más, esa es una opinión extremadamente subjetiva, así que si usted y sus colegas encuentran que el ternario es muy legible, adelante.

Mike Stone
fuente
1
Sin embargo, eso no es exactamente lo mismo. En el segundo ejemplo, está comprimiendo las tres declaraciones en una línea. Eso es lo que disminuye la legibilidad, no el operador ternario.
ilitirit
Es justo, actualicé para incorporar su comentario, pero todavía me siento abarrotado ... pero de nuevo, es subjetivo ... No digo que ternary no sea legible, digo que no es legible para mí (99 % del tiempo)
Mike Stone
3

Sólo cuando:

$ var = (simple> prueba? simple_result_1: simple_result_2);

BESO.

Jared Farrish
fuente
3

Normalmente uso en cosas 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
fuente
Por supuesto, en la mayoría de los idiomas, tampoco necesitaría la parte "== verdadero" de ese ternario.
Michael Haren
Me doy cuenta de eso, aunque tiendo a ponerlo solo para hacer que el código sea más legible ya que el compilador debería optimizarlo de la misma manera que sin el == verdadero de todos modos
KPexEA
en ningún idioma puede necesitar "== verdadero"
niXar
Tuve dificultades para decidir si votar o no. El ejemplo es bueno, pero el == VERDADERO es algo que no puedo soportar ver en el código de otras personas.
Peter Perháč
3

Como otros han señalado, son agradables para condiciones simples y cortas. Me gustan especialmente los valores predeterminados (como el || y / o el uso en javascript y python), p. Ej.

int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;

Otro uso común es inicializar una referencia en C ++. Como las referencias deben declararse e inicializarse en la misma declaración, no puede usar una declaración if.

SomeType& ref = pInput ? *pInput : somethingElse;
maccullt
fuente
2
Es sorprendente que esta sea la primera mención de referencias de inicialización, que es uno de los pocos lugares donde "if" no se puede usar en lugar de?:. (Supongo que porque esta no es una pregunta específica de C ++ ...) También son útiles en las listas de inicialización de constructores, por la misma razón.
j_random_hacker
2

Trato a los operadores ternarios como GOTO. Tienen su lugar, pero son algo que generalmente debe evitar para que el código sea más fácil de entender.

Dan Walker
fuente
2

Recientemente vi una variación en los operadores ternarios (bueno, más o menos) que hacen que la variante estándar "()?:" Parezca ser un modelo de claridad:

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

o, para dar un ejemplo más tangible:

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

Eso sí, esto es Javascript, por lo que cosas como esa podrían no ser posibles en otros idiomas (afortunadamente).

pilsetnieks
fuente
1
wow, eso es horrible! ¡imagina anidar un par de esos juntos! La única cosa vagamente útil que puedo ver con eso es si tuviera una función que devolviera una matriz de 2 elementos: var Name = getNames () [Gender == 'm']; ... ¡pero eso es MENOS legible!
nickf
2

Por simple si los casos, me gusta usarlo. En realidad, es mucho más fácil leer / codificar, por ejemplo, como parámetros para funciones o cosas por el estilo. También para evitar la nueva línea que me gusta mantener con todos mis if / else.

Anidar sería un gran NO-NO en mi libro.

Entonces, resumiendo, para un solo si / si no, usaré el operador ternario. Para otros casos, un if / else if / else (o switch) regular

Rodrigo Gómez
fuente
2

Me gusta el caso especial de Groovy del operador ternario, llamado operador de Elvis:?:

expr ?: default

Este código se evalúa como expr si no es nulo, y por defecto si lo es. Técnicamente no es realmente un operador ternario, pero definitivamente está relacionado con él y ahorra mucho tiempo / tipeo.

Steve Losh
fuente
Sí, también me encanta: está ??en C #, el operador de fusión nula: stackoverflow.com/questions/278703/…
Jarrod Dixon
2

Para tareas simples como asignar un valor diferente dependiendo de una condición, son geniales. No los usaría cuando hay expresiones más largas dependiendo de la condición aunque.

Svet
fuente
2

Muchas respuestas han dicho, depende . Encuentro que si la comparación ternaria no es visible en un escaneo rápido del código, entonces no debería usarse.

Como cuestión secundaria, también podría señalar que su existencia misma es en realidad un poco anomólica debido al hecho de que en C, las pruebas de comparación son una declaración. En Icon, la ifconstrucción (como la mayoría de Icon) es en realidad una expresión. Entonces puedes hacer cosas como:

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

... que encuentro mucho más legible que un operador de comparación de ternery. :-)

Recientemente hubo una discusión sobre la posibilidad de agregar el ?:operador a Icon, pero varias personas señalaron correctamente que no había absolutamente ninguna necesidad debido a la forma en que iffunciona.

Lo que significa que si pudiera hacer eso en C (o en cualquiera de los otros lenguajes que tienen el operador de ternery), entonces, de hecho, no necesitaría el operador de ternery.

staticsan
fuente
2

Si usted y sus compañeros de trabajo entienden lo que hacen y no se crean en grupos masivos, creo que hacen que el código sea menos complejo y más fácil de leer porque simplemente hay menos código.

La única vez que creo que los operadores ternarios hacen que el código sea más difícil de entender es cuando tienes más de 3 o 4 en una línea. La mayoría de las personas no recuerdan que tienen una precedencia correcta y cuando tienes una pila de ellas, hace que leer el código sea una pesadilla.

Alex
fuente