¿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?


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;

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.


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.


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).


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.


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.


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.


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.


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.


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.


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.


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!


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;

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.


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.


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.


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");

¿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).


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


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.


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

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

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;

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.


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).


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


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.


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.


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.


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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.