Pour ternaire ou de ne pas ternaire? [fermé]

Je suis personnellement un défenseur de l'opérateur ternaire: ()? :; Je me rends compte qu'il a sa place, mais j'ai rencontré de nombreux programmeurs qui sont complètement contre de l'utiliser, et certains qui l'utilisent trop souvent.

Quels sont vos sentiments à ce sujet? Quel code intéressant avez-vous vu l'utiliser?

172
demandé sur pixel 2008-10-02 03:27:46

30 réponses

Utiliser pour expressions simples seulement:

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

Ne pas enchaîner ou imbriquer opérateurs ternaires car il est difficile à lire et déroutant:

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

De plus, lorsque vous utilisez l'opérateur ternaire, envisagez de formater le code d'une manière qui améliore la lisibilité:

int a = (b > 10) ? some_value                 
                 : another_value;
215
répondu marcospereira 2010-02-16 01:14:10

Cela rend le débogage légèrement plus difficile car vous ne pouvez pas placer de points d'arrêt sur chacune des sous-expressions. Je l'utilise rarement.

113
répondu David Segonds 2008-10-02 00:41:25

Je les aime, surtout dans les langues à sécurité de type.

Je ne vois pas comment cela:

int count = (condition) ? 1 : 0;

Est plus difficile que cela:

int count;

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

Modifier -

Je dirais que les opérateurs ternaires rendent tout moins complexe et plus soigné que l'alternative.

77
répondu Ian P 2009-02-11 01:37:55

Enchaîné je suis bien avec-imbriqué, pas tellement.

J'ai tendance à les utiliser plus en C simplement b / C ils sont une instruction if qui a une valeur, donc elle réduit les répétitions inutiles ou les variables:

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

Plutôt que

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

Dans des missions comme celle-ci, je trouve que c'est moins à refactoriser, et plus clair.

Quand je travaille dans ruby d'autre part, je suis plus susceptible d'utiliser if...else...end parce que c'est aussi une expression.

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

(bien que, certes, pour quelque chose de ce simple, je pourrais juste utiliser l'opérateur ternaire de toute façon).

38
répondu rampion 2008-10-02 04:32:38

L'opérateur ternaire ?: n'est qu'un équivalent fonctionnel de la construction procédurale if. Donc, tant que vous n'utilisez pas d'expressions ?: imbriquées, les arguments pour/contre la représentation fonctionnelle de toute opération s'appliquent ici. Mais l'imbrication des opérations ternaires peut entraîner un code carrément déroutant (exercice pour le lecteur: essayez d'écrire un analyseur qui gérera les conditions ternaires imbriquées et vous apprécierez leur complexité).

Mais il y a beaucoup de situations où l'utilisation conservatrice de l'opérateur ?: peut entraîner un code qui est en fait plus facile à lire qu'autrement. Par exemple:

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

Maintenant, comparez cela avec ceci:

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

Comme le code est plus compact, il y a moins de bruit syntaxique, et en utilisant judicieusement l'opérateur ternaire (c'est seulement en relation avec la propriété reverseOrder) le résultat final n'est pas particulièrement laconique.

38
répondu Ryan Delucchi 2012-08-02 17:13:18

C'est une question de style, vraiment; les règles subconscientes que j'ai tendance à suivre sont:

  • évaluer Seulement 1 expression - si foo = (bar > baz) ? true : false, mais PAS foo = (bar > baz && lotto && someArray.Contains(someValue)) ? true : false
  • Si je l'utilise pour la logique d'affichage, par exemple <%= (foo) ? "Yes" : "No" %>
  • ne l'utilise vraiment que pour l'affectation; jamais de logique de flux (donc jamais (foo) ? FooIsTrue(foo) : FooIsALie(foo) ) la logique de flux dans ternaire est elle-même un mensonge, ignorez ce dernier point.

Je l'aime parce qu'il est concis et élégant pour les opérations d'affectation simples.

24
répondu Keith Williams 2008-10-02 14:51:28

Comme tant de questions d'opinion, la réponse est inévitablement: Cela dépend

, Pour quelque chose comme:

return x ? "Yes" : "No";

Je pense que c'est beaucoup plus concis (et plus rapide pour moi pour analyser) que:

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

Maintenant, si votre expression conditionnelle est complexe, alors l'opération ternaire n'est pas un bon choix. Quelque chose comme:

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

N'Est pas un bon candidat pour l'opérateur ternaire.

En aparté, si vous êtes un programmeur C, GCC a en fait un extension {[24] } qui vous permet d'exclure la partie if-true du ternaire, comme ceci:

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

, Qui va ensemble x à y en supposant que y n'est pas NULL. De bonnes choses.

18
répondu Sean Bright 2009-02-11 01:55:57

Dans mon esprit, il est logique d'utiliser l'opérateur ternaire dans les cas où une expression est nécessaire.

Dans d'autres cas, il semble que l'opérateur ternaire diminue la clarté.

12
répondu John Mulder 2008-10-01 23:29:23

Par la mesure de complexité cyclomatique, l'utilisation de if déclarations ou l'opérateur ternaire sont équivalentes. Donc, par cette mesure, la réponse est non, la complexité serait exactement la même qu'avant.

Par d'autres mesures telles que la lisibilité, la maintenabilité et le séchage (ne pas répéter), l'un ou l'autre choix peut s'avérer meilleur que l'autre.

11
répondu Greg Hewgill 2009-02-11 01:57:38

Je l'utilise assez souvent dans des endroits où je suis contraint de travailler dans un constructeur - par exemple, les nouvelles constructions.net 3.5 LINQ to XML - pour définir des valeurs par défaut lorsqu'un paramètre optionnel est null.

Exemple Artificiel:

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

Ou (merci asterite)

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

Peu importe si vous utilisez l'opérateur ternaire ou non, assurez-vous que votre code est lisible est la chose importante. Toute construction peut être rendue illisible.

10
répondu Erik Forbes 2008-10-02 04:45:29

J'utilise l'opérateur ternaire où je peux, à moins que cela ne rende le code extrêmement difficile à lire, mais c'est généralement juste une indication que mon code pourrait utiliser un peu de refactoring.

Il me déroute toujours comment certaines personnes pensent que l'opérateur ternaire est une fonctionnalité "cachée" ou est quelque peu mystérieuse. C'est l'une des premières choses que j'ai apprises quand je commence à programmer en C, et je ne pense pas que cela diminue la lisibilité du tout. C'est une partie naturelle de la langue.

9
répondu ilitirit 2008-10-01 23:45:11

Je suis d'accord avec jmulder: il ne devrait pas être utilisé à la place d'un if, mais il a sa place pour l'expression de retour ou dans une expression:

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

Le premier n'est qu'un exemple, un meilleur support I18N du pluriel devrait être utilisé!

7
répondu PhiLho 2008-10-02 14:15:00

Si vous utilisez l'opérateur ternaire pour une simple affectation conditionnelle, je pense que c'est bien. Je l'ai vu (ab) utilisé pour contrôler le flux de programme sans même faire une affectation, et je pense que cela devrait être évité. Utilisez une instruction if dans ces cas.

6
répondu Bill the Lizard 2009-02-11 02:32:38

(Hack du jour)

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

, Alors vous pouvez faire si-alors-sinon comme expression:

int b = IF(condition1)    res1
        ELSE IF(condition2)  res2
        ELSE IF(conditions3) res3
        ELSE res4;
6
répondu John John 2012-08-02 15:17:03

Je pense que l'opérateur ternaire devrait être utilisé en cas de besoin. C'est évidemment un choix très subjectif, mais je trouve qu'une expression simple (spécialement comme expression de retour) est beaucoup plus claire qu'un test complet. Exemple en C / C++:

return (a>0)?a:0;

Par Rapport à:

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

Vous avez également le cas où la solution est entre l'opérateur ternaire et la création d'une fonction. Par exemple en Python:

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

L'alternative est:

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

Il est assez nécessaire que dans Python (comme un exemple), un tel idiome pourrait être vu régulièrement:

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

Cette ligne utilise les propriétés des opérateurs logiques en Python: ils sont paresseux et renvoie la dernière valeur calculée si elle est égale à l'état final.

5
répondu PierreBdR 2008-10-01 23:39:30

Je les aime bien. Je ne sais pas pourquoi, mais je me sens très cool quand j'utilise l'expression ternaire.

5
répondu JimDaniel 2009-02-11 01:48:09

J'ai vu de telles bêtes comme (c'était en fait bien pire puisque c'était isValidDate et vérifié mois et jour aussi, mais je ne pouvais pas être dérangé en essayant de me souvenir de tout):

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

Où, clairement, une série d'instructions if aurait été meilleure (bien que celle-ci soit toujours meilleure que la version macro que j'ai vue une fois).

Cela ne me dérange pas pour de petites choses comme:

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

Ou même des choses légèrement délicates comme:

printf ("Deleted %d file%s\n", n, (n == 1) ? "" : "s");
5
répondu paxdiablo 2009-02-11 02:04:18

J'aime utiliser l'opérateur dans le code de débogage pour imprimer les valeurs d'erreur, donc je n'ai pas besoin de les rechercher tout le temps. Habituellement, je le fais pour les impressions de débogage qui ne resteront pas une fois que j'ai terminé le développement.

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
répondu indiv 2008-10-01 23:56:53

Je n'utilise presque jamais l'opérateur ternaire car chaque fois que je l'utilise, cela me fait toujours penser beaucoup plus que ce que je dois faire plus tard lorsque j'essaie de le maintenir.

J'aime éviter la verbosité, mais quand cela rend le code beaucoup plus facile à ramasser, je vais opter pour la verbosité.

Considérez:

String name = firstName;

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

name += " " + lastName;

Maintenant, c'est un peu verbeux, mais je le trouve beaucoup plus lisible que:

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

Ou:

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

Il semble juste compresser trop d'informations dans trop peu d'espace, sans le rendre clair ce qui se passe. Chaque fois que je vois l'opérateur ternaire utilisé, j'ai toujours trouvé une alternative qui semblait beaucoup plus facile à lire... là encore, c'est une opinion extrêmement subjective, donc si vous et vos collègues trouvez ternaire très lisible, allez-y.

4
répondu Mike Stone 2008-10-01 23:57:38

Eh bien, la syntaxe pour cela est horrible. Je trouve les ifs fonctionnels très utiles, et rend souvent le code plus lisible.

Je suggère de faire une macro pour la rendre plus lisible, mais je suis sûr que quelqu'un peut trouver un horrible cas de bord (comme il y en a toujours avec CPP).

3
répondu Marcin 2008-10-01 23:31:55

Seulement quand:

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

Baiser.

3
répondu Jared Farrish 2008-10-02 00:43:58

J'utilise généralement dans des choses comme ceci:

before:

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

after:

    drawtext(x,y,isheader==true?WHITE:BLUE,string);
3
répondu KPexEA 2008-10-02 03:12:41

Comme d'autres l'ont souligné, ils sont agréables pour des conditions simples et courtes. J'aime particulièrement pour les valeurs par défaut (un peu comme le || et ou l'utilisation de javascript et python), par exemple:

int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;

Une autre utilisation courante consiste à initialiser une référence en C++. Depuis références doivent être déclarées et initialisées dans la même déclaration, vous ne pouvez pas utiliser une instruction if.

SomeType& ref = pInput ? *pInput : somethingElse;
3
répondu maccullt 2009-02-11 02:40:35

Je traite les opérateurs ternaires un peu comme GOTO. Ils ont leur place, mais ils sont quelque chose que vous devriez généralement éviter pour rendre le code plus facile à comprendre.

2
répondu Dan Walker 2008-10-01 23:33:54

J'ai récemment vu une variation sur les opérateurs ternaires (enfin, en quelque sorte) qui font la norme" ()? : "variant semble être un parangon de clarté:

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

Ou, pour donner un exemple concret:

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

Rappelez-vous, C'est Javascript, donc des choses comme ça pourraient ne pas être possibles dans d'autres langues (heureusement).

2
répondu pilsetnieks 2008-10-02 00:12:42

Pour les cas simples, j'aime l'utiliser. En fait, il est beaucoup plus facile de lire/coder par exemple en tant que paramètres pour des fonctions ou des choses comme ça. Aussi pour éviter la nouvelle ligne que j'aime garder avec tout mon if / else.

Neseting ce serait un grand NON-NON dans mon livre.

Donc, en reprenant, pour un seul if / else je vais utiliser l'opérateur ternaire. Pour les autres cas, un if/else if/else (ou switch)

2
répondu Rodrigo Gómez 2008-10-02 01:21:13

J'aime le cas particulier de Groovy de l'opérateur ternaire, appelé l'opérateur Elvis:?:

expr ?: default

Ce code est évalué à expr s'il n'est pas null, et par défaut s'il l'est. Techniquement, ce n'est pas vraiment un opérateur ternaire, mais c'est définitivement lié à cela et permet d'économiser beaucoup de temps/Dactylographie.

2
répondu Steve Losh 2008-10-02 14:18:03

Pour des tâches simples comme l'attribution d'une valeur différente en fonction d'une condition, elles sont géniales. Je ne les utiliserais pas quand il y a des expressions plus longues en fonction de la condition tho.

2
répondu Svet 2009-02-11 01:39:44

Tant de réponses ont dit, Cela dépend . Je trouve que si la comparaison ternaire n'est pas visible dans une analyse rapide du code, elle ne devrait pas être utilisée.

En tant que problème secondaire, je pourrais également noter que son existence même est en fait un peu anomolique en raison du fait qu'en C, le test de comparaison est une déclaration. Dans Icon, la construction if (comme la plupart des Icon) est en fait une expression. Donc, vous pouvez faire des choses comme:

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

... que je trouve beaucoup plus lisible qu'un opérateur de comparaison ternery. :-)

Il y a eu récemment une discussion sur la possibilité d'ajouter l'opérateur ?: à Icon, mais plusieurs personnes ont souligné à juste titre qu'il n'y avait absolument pas besoin en raison de la façon dont if fonctionne.

Ce qui signifie que si vous pouviez le faire en C (ou dans l'une des autres langues qui ont l'opérateur ternery), alors vous n'auriez pas du tout besoin de l'opérateur ternery.

2
répondu staticsan 2009-02-11 02:50:07

Si vous et vos collègues comprenez ce qu'ils font et qu'ils ne sont pas créés en groupes massifs, je pense qu'ils rendent le code moins complexe et plus facile à lire car il y a simplement moins de code.

La seule fois où je pense que les opérateurs ternaires rendent le code plus difficile à comprendre est quand vous avez plus de 3 ou 4 dans une ligne. La plupart des gens ne se souviennent pas qu'ils sont une priorité basée sur le droit et quand vous en avez une pile, Cela fait de la lecture du code un cauchemar.

2
répondu Alex 2011-04-30 09:01:31