Question

Je suis personnellement partisan de l'opérateur ternaire: ()? :; Je me rends bien compte qu’il a sa place, mais j’ai rencontré beaucoup de programmeurs qui sont totalement opposés à l’utiliser, et certains l’utilisent trop souvent.

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

Était-ce utile?

La solution

Utilisez-le pour les expressions simples uniquement :

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

Ne chaînez pas et ne nichez pas d'opérateurs ternaires, car il est difficile à lire et confus:

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 de manière à améliorer la lisibilité:

int a = (b > 10) ? some_value                 
                 : another_value;

Autres conseils

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

Je les aime, en particulier dans les langues sans danger pour les caractères.

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 simple que l’alternative.

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

J'ai tendance à les utiliser davantage en C simplement parce qu'ils sont une instruction if qui a de la valeur, ce qui réduit les répétitions ou les variables inutiles:

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.

Par contre, lorsque je travaille dans ruby, je suis plus susceptible d’utiliser if...else...end car 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 d'aussi simple, je pourrais simplement utiliser l'opérateur ternaire de toute façon).

L'opérateur ternaire ?: est simplement un équivalent fonctionnel de la construction procédurale if. Ainsi, 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. Cependant, l'imbrication d'opérations ternaires peut donner lieu à un code totalement déroutant (exercice pour le lecteur: essayez d'écrire un analyseur qui gérera les conditions ternaires imbriquées et vous en apprécierez la complexité).

Mais il existe de nombreuses situations dans lesquelles une utilisation conservatrice de l'opérateur <=> peut générer un code réellement plus facile à lire . 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;              
}

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

Plus le code est compact, moins il y a de bruit syntaxique, et en utilisant l'opérateur ternaire à bon escient (uniquement en relation avec la propriété reverseOrder ), le résultat final n'est pas particulièrement concis.

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

  • Évaluez seulement 1 expression - donc 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 ex. <%= (foo) ? "Yes" : "No" %>
  • Ne l'utilisez vraiment que pour l'affectation; Jamais la logique de flux (donc jamais (foo) ? FooIsTrue(foo) : FooIsALie(foo)) La logique de flux en ternaire est elle-même un mensonge, ignorez ce dernier point.

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

Comme pour de nombreuses 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 à analyser) que:

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

Désormais, si votre expression conditionnelle est complexe, 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 passant, si vous êtes programmeur C, GCC a en réalité une extension qui vous permet d'exclure la partie if-true du ternaire, comme ceci:

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

Qui définira x sur y en supposant que NULL n'est pas <=>. Bonnes choses.

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

Par la mesure de la complexité cyclomatique , de l’utilisation de if instructions ou de l’opérateur ternaire sont équivalents. Donc, par cette mesure, la réponse est non , la complexité serait exactement la même qu'auparavant.

Par d’autres mesures telles que la lisibilité, la maintenabilité et le DRY (Don't-Repeat-Yourself), l’un ou l’autre choix peut se révéler meilleur que l’autre.

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 les valeurs par défaut lorsqu'un paramètre facultatif est null.

Exemple élaboré:

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

Que vous utilisiez ou non l'opérateur ternaire, il est important de vous assurer que votre code est lisible. Toute construction peut être rendue illisible.

J'utilise l'opérateur ternaire autant que je peux, à moins que cela ne rende le code extrêmement difficile à lire, mais dans ce cas, c'est simplement une indication que mon code pourrait utiliser un peu de refactoring.

Cela me surprend toujours de voir comment certaines personnes pensent que l'opérateur ternaire est un & "caché &"; caractéristique ou est un peu mystérieux. C'est l'une des premières choses que j'ai apprises lorsque je commence à programmer en C, et je ne pense pas que cela diminue la lisibilité. C'est une partie naturelle de la langue.

Je suis d'accord avec jmulder: il ne devrait pas être utilisé à la place d'un if, mais il a sa place dans 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é!

(Le piratage du jour)

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

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

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

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

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 une expression de retour) est beaucoup plus claire qu'un test complet. Exemple en C / C ++:

return (a>0)?a:0;

Comparé à:

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

Vous avez également le cas où la solution se situe 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 la suivante:

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

Il est suffisant qu’en Python (à titre d’exemple) un tel idiome puisse ê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 lazy et retournent la dernière valeur calculée si elle est égale à l'état final.

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

J'ai vu des bêtes comme celle-ci (c'était en fait bien pire depuis que c'était isValidDate et vérifié mois et jour aussi, mais je ne pouvais pas être dérangé d'essayer de me souvenir de tout ça):

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

où, à l’évidence, une série de déclarations if aurait été meilleure (bien que celle-ci soit encore 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");

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

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

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

J'aime éviter les commentaires verbaux, mais quand cela rendra le code beaucoup plus facile à lire, je choisirai les commentaires verbaux.

Considérez:

String name = firstName;

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

name += " " + lastName;

Maintenant, c'est un peu bavard, 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;

Cela semble simplement compresser trop d’informations dans un espace insuffisant, sans préciser ce qui se passe. À chaque fois que je vois un opérateur ternaire utilisé, j'ai toujours trouvé une alternative qui semblait beaucoup plus facile à lire. Là encore, il s'agit d'un avis extrêmement subjectif. Si vous et vos collègues trouvez que ternary est très lisible, foncez.

Eh bien, la syntaxe est horrible. Je trouve les fonctions fonctionnelles très utiles et rend souvent le code plus lisible.

Je suggérerais de créer une macro pour la rendre plus lisible, mais je suis sûr que quelqu'un peut présenter un cas épouvantable (comme il en existe toujours avec le RPC).

Seulement quand:

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

KISS.

J'utilise généralement dans des choses comme celle-ci:

before:

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

after:

    drawtext(x,y,isheader==true?WHITE:BLUE,string);

Comme d'autres l'ont déjà souligné, ils conviennent aux conditions simples et courtes. Je les aime particulièrement pour les valeurs par défaut (un peu comme l’utilisation de || et de ou en javascript et python), par exemple.

int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;

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

SomeType& ref = pInput ? *pInput : somethingElse;

Je traite beaucoup les opérateurs ternaires comme GOTO. Ils ont leur place, mais ils doivent généralement être évités pour rendre le code plus facile à comprendre.

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

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

ou, pour donner un exemple plus concret:

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

Remarquez, c’est du Javascript, donc des choses comme cela pourraient ne pas être possibles dans d’autres langues (heureusement).

Pour les cas simples, j'aime bien 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, j'aime rester avec tous mes if / else.

Ce serait un gros NON-NON dans mon livre.

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

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

expr ?: default

Ce code est évalué à expr s'il n'est pas null et à défaut s'il le est. Techniquement, il ne s’agit pas vraiment d’un opérateur ternaire, mais il est clairement lié à celui-ci et permet de gagner beaucoup de temps / de frappe.

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

Beaucoup de réponses ont été exprimées, 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 réalité une anomalie, car en C, le test de comparaison est une affirmation. Dans Icon, la construction if (comme la plupart des icônes) est en réalité une expression. Pour que vous puissiez 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. : -)

On a récemment discuté de la possibilité d’ajouter l’opérateur ?: à Icon, mais plusieurs personnes ont fait remarquer à juste titre qu’il n’était absolument pas nécessaire en raison du fonctionnement <=>.

Ce qui signifie que si vous pouviez le faire en C (ou dans l’une des autres langues utilisant l’opérateur ternery), vous n’auriez en fait pas besoin de cet opérateur.

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 tout simplement moins de code.

La seule fois où je pense que les opérateurs ternaires rendent le code plus difficile à comprendre, c’est lorsque vous avez plus de 3 ou 4 sur une ligne. La plupart des gens ne se souviennent pas qu'ils constituent une priorité correcte et lorsque vous en avez une pile, la lecture du code devient un cauchemar.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top