Est-il jamais acceptable qu'un conditionnel ait des effets secondaires? [fermé]

10

Je prends un cours sur les structures de données intermédiaires comme condition préalable à l'entrée au programme CS MS dans une université dont tout le monde en Amérique a entendu parler. Une ligne de code écrite en classe a attiré mon attention:

if (a > 33 | b++ < 54) {...}

Cela ne passerait pas un examen du code sur mon lieu de travail. Si vous avez écrit un code comme celui-ci dans une interview, ce serait une grève importante contre vous. (En plus d'être un conditionnel avec des effets secondaires, il est intelligent au détriment de la clarté.)

En fait, je n'ai jamais vu de conditionnel avec des effets secondaires, et Google ne se présente pas beaucoup non plus. Un autre élève est resté derrière après le cours pour poser des questions à ce sujet également, donc je ne suis pas le seul à penser que c'était bizarre. Mais le professeur était assez catégorique qu'il s'agissait d'un code acceptable et qu'il écrirait quelque chose comme ça au travail. (Son travail de FT est en tant que SWE principal dans une entreprise dont vous avez tous entendu parler.)

Je ne peux pas imaginer un monde dans lequel cette ligne de code serait jamais acceptable, encore moins souhaitable. Ai-je tort? Est-ce correct? Qu'en est-il du cas plus général: les conditions avec effets secondaires? Est-ce que ça va?

rianjs
la source
7
Cette ligne doit être supprimée de l'orbite. Deux fois pour faire bonne mesure.
Blrfl
8
A nit: Un seul tuyau (barre verticale) est un bit ou dans la plupart des langues, plutôt qu'un "ou" logique. Il ne court-circuite pas si le côté gauche est vrai. Étant donné que ce conditionnel a des effets secondaires sur le côté droit, cela fait une différence particulièrement importante dans le résultat.
Jonathan Eunice
2
Il existe des idiomes utilisés dans diverses langues qui entrent dans cette catégorie, mais parce qu'ils sont "bien connus" ou "normaux" ne posent pas de problèmes. La ligne dans la question ne semble pas tomber dans la catégorie d'utilisation idiomatique, donc je l'éviterais.
Jaydee
2
@JonathanEunice, oui, certaines personnes étaient confuses au sujet de l'évaluation des courts-circuits. Pas une faute de ma part.
rianjs
5
Regarde le bon côté. Vous connaissez maintenant une autre entreprise où vous ne voulez PAS interviewer.
John R. Strohm

Réponses:

23

Il y a un effet secondaire semi-conditionnel auquel je pense que c'est correct:while(iter.MoveNext())

Cela dit, je pense que cela tombe principalement dans la catégorie " jamais un très gros qualificatif". Je peux penser à quelques rares cas où je l'ai vu être acceptable, mais en général c'est vil et à éviter.

Je ne peux pas non plus penser à un scénario où cette ligne particulière serait acceptable, mais je ne peux pas non plus penser à un scénario où cette ligne particulière serait utile , il est donc difficile d'imaginer le contexte dans lequel elle se trouve.

Telastyn
la source
C'était juste une ligne jetable dans une méthode pendant le cours. Il n'était pas destiné à faire quoi que ce soit d'utile.
rianjs
4
De manière équivalente, les while(v = *p++)analyses de style C / C ++ à travers un tableau terminé par zéro (par exemple la chaîne C) sont assez courantes et largement acceptées.
Phil Miller
3
J'ai souvent considéré les conditions de boucle de la forme while(c = input.read() != '\n')comme raisonnablement idiomatiques.
1
Il peut y avoir quelques idiomes acceptables communs, mais clairement "être intelligent au détriment de la clarté" tombe dans le camp JAMAIS.
Julia Hayward du
J'ai totalement oublié iter.MoveNext (). Un cas tout à fait raisonnable pour un conditionnel ayant un effet secondaire. Merci!
rianjs
8

Dans mon monde, une lecture à partir de la mémoire peut être considérée comme un effet secondaire (par exemple IO mappé en mémoire).

Maintenant, considérez ce qui suit:

    while( ( *memory_mapped_device_status_register & READY_FLAG) == 0) {
       // Wait
    }

Et comparer à:

    status = *memory_mapped_device_status_register;
    while( ( status & READY_FLAG) == 0) {
        // Wait
        status = *memory_mapped_device_status_register;
    }

L'évitement de l'effet secondaire (la lecture) dans la condition a-t-il aidé à la lisibilité; ou a-t-il simplement dupliqué du code et ajouté de l'encombrement?

Ce n'est pas OK pour qu'une condition ait des effets secondaires (si cela rend le code moins lisible) et c'est aussi OK pour une condition d'avoir des effets secondaires (si cela rend le code plus lisible). Le facteur clé est la "lisibilité". Tout le reste est des règles créées par des imbéciles dans une tentative malavisée d'améliorer la lisibilité (tout en ayant souvent l'effet inverse).

Brendan
la source
3

Comme toujours avec de telles questions, c'est une question de degré. S'il y avait une preuve sans équivoque que tout effet secondaire dans une ifexpression toujours conduit à un code pire, alors il ne serait pas légal de créer ces expressions. Les concepteurs de langage peuvent être des humains idéosyncratiques et faillibles, mais ils ne sont pas si stupides.

Cela dit, quels sont les exemples d'effets secondaires justifiés dans un if? Par exemple, supposons que vous êtes légalement tenu d'enregistrer tous les accès à la propriété Pd'une entité Eà des fins d'audit. (Imaginez que vous travaillez dans une usine d'enrichissement d'uranium, et qu'il existe des contrôles juridiques très stricts sur ce que votre code est autorisé à faire et comment il est censé le faire.) Ensuite, tout ce ifqui vérifie cette propriété entraînera l'effet secondaire de la journal d'audit en cours d'extension.

C'est une préoccupation transversale assez claire, cela n'affecte pas votre raisonnement sur l'état du programme (beaucoup), et vous pouvez l'implémenter de sorte qu'il soit complètement invisible et sans distraction lorsque vous passez en revue la ligne avec le if(caché dans l'accesseur, ou encore mieux via AOP). Je dirais que c'est un cas assez clair d'un effet secondaire qui n'est pas un problème. Des situations similaires peuvent être imaginées lorsque vous souhaitez simplement compter les exécutions de branches à des fins de profilage, etc.

Plus ces circonstances atténuantes disparaissent, plus la construction deviendra étrangère. Si un type de boucle particulier (par exemple if((c = getc()) == 'x') { quit(); }est bien connu et accepté par la communauté linguistique, alors c'est beaucoup moins un problème que lorsque vous l'inventez spontanément, etc. Votre exemple de ligne ne correspond pas à cette norme, mais je pourrais imaginer beaucoup, beaucoup plus horribles que je ne taperai même pas, ils sont tellement horribles.

Kilian Foth
la source
2

Bien que le code soit vraiment mauvais, il a l'avantage d'être plus simple (et peut-être plus rapide si vous n'avez pas un bon compilateur d'optimisation) que son équivalent if (a > 33 | b < 54) {b++; ...} else b++;

mais bien sûr il est possible de l'optimiser pour les suivants (mais attention! celui-ci a un comportement différent en cas de débordement!): b++; if (a > 33 | b < 53) {...}

Franki
la source