Parfois, une if
instruction peut être assez compliquée ou longue, donc pour des raisons de lisibilité, il est préférable d'extraire les appels compliqués avant le if
.
par exemple ceci:
if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
// do stuff
}
dans ce
bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();
if (b1 || b2)
{
//do stuff
}
(l'exemple fourni n'est pas si mal, c'est juste à titre d'illustration ... imaginez d'autres appels avec plusieurs arguments, etc.)
Mais avec cette extraction, j'ai perdu l'évaluation des courts-circuits (SCE).
- Est-ce que je perds vraiment SCE à chaque fois? Existe-t-il un scénario dans lequel le compilateur est autorisé à «l'optimiser» tout en fournissant SCE?
- Existe-t-il des moyens de conserver la lisibilité améliorée du deuxième extrait de code sans perdre SCE?
Réponses:
Une solution naturelle ressemblerait à ceci:
Cela présente les avantages d'être facile à comprendre, d'être applicable à tous les cas et d'avoir un comportement de court-circuit.
C'était ma solution initiale: un bon modèle dans les appels de méthode et les corps de boucle for est le suivant:
On obtient les mêmes avantages de performances que l'évaluation des courts-circuits, mais le code semble plus lisible.
la source
if
" est aussi un signe que votre fonction ou méthode est trop grande et devrait être divisée en plus petites. Ce n'est pas toujours la meilleure façon mais très souvent!b2
correctement et vous obtiendrezsomeConditionAndSomeotherConditionIsTrue
, pas super significatif. De plus, je dois garder un tas de variables sur ma pile mentale pendant cet exercice (et jusqu'à ce que j'arrête de travailler dans ce cadre). J'irais avecSJuan76
la solution numéro 2 ou tout simplement mettre le tout dans une fonction.J'ai tendance à décomposer les conditions sur plusieurs lignes, c'est-à-dire:
Même lorsque vous traitez avec plusieurs opérateurs (&&), il vous suffit d'avancer l'indentation avec chaque paire de parenthèses. SCE intervient toujours - pas besoin d'utiliser des variables. Écrire du code de cette façon me le rendait beaucoup plus lisible depuis des années déjà. Exemple plus complexe:
la source
Si vous avez de longues chaînes de conditions et que conserver une partie du court-circuit, vous pouvez utiliser des variables temporaires pour combiner plusieurs conditions. En prenant votre exemple, il serait possible de faire par exemple
Si vous avez un compilateur compatible C ++ 11, vous pouvez utiliser des expressions lambda pour combiner des expressions en fonctions, comme ci-dessus:
la source
1) Oui, vous n'avez plus SCE. Sinon, tu aurais ça
fonctionne dans un sens ou dans l'autre selon qu'il y a une
if
déclaration plus tard. Beaucoup trop complexe.2) Ceci est basé sur une opinion, mais pour des expressions raisonnablement complexes, vous pouvez faire:
Si cela est trop complexe, la solution évidente est de créer une fonction qui évalue l'expression et l'appelle.
la source
Vous pouvez aussi utiliser:
et SCE fonctionnera.
Mais ce n'est pas beaucoup plus lisible que par exemple:
la source
b = b || otherComplicatedStuff();
spécifiquement et @SargeBorsch a fait une modification pour supprimer SCE. Merci de m'avoir signalé ce changement @Ant.Je ne pense pas qu'une telle optimisation soit autorisée; surtout
OtherComplicatedFunctionCall()
pourrait avoir des effets secondaires.Je préfère le refactoriser en une fonction ou une variable avec un nom descriptif; ce qui préservera à la fois l'évaluation des courts-circuits et la lisibilité:
Et lorsque nous implémentons en
getSomeResult()
fonction deSomeComplicatedFunctionCall()
etOtherComplicatedFunctionCall()
, nous pourrions les décomposer de manière récursive s'ils sont encore compliqués.la source
Non, vous ne le faites pas, mais c'est appliqué différemment:
Ici, le compilateur ne s'exécutera même pas
OtherComplicatedFunctionCall()
s'ilSomeComplicatedFunctionCall()
retourne true.Ici, les deux fonctions vont exécuter parce qu'ils doivent être stockés dans
b1
etb2
. Ffb1 == true
alorsb2
ne sera pas évalué (SCE). MaisOtherComplicatedFunctionCall()
a déjà été exécuté.Si
b2
n'est utilisé nulle part ailleurs, le compilateur peut être assez intelligent pour intégrer l'appel de fonction à l'intérieur du if si la fonction n'a pas d'effets secondaires observables.Ça dépend. Avez-vous besoin
OtherComplicatedFunctionCall()
d'exécuter en raison d'effets secondaires ou si la performance de la fonction est minime, vous devez utiliser la deuxième approche pour la lisibilité. Sinon, tenez-vous-en à SCE par la première approche.la source
Une autre possibilité qui court-circuite et a les conditions en un seul endroit:
Vous pouvez mettre la boucle dans une fonction et laisser la fonction accepter une liste de conditions et afficher une valeur booléenne.
la source
Très étrange: vous parlez de lisibilité lorsque personne ne mentionne l'utilisation du commentaire dans le code:
En plus de cela, je précède toujours mes fonctions avec quelques commentaires, sur la fonction elle-même, sur son entrée et sa sortie, et parfois je mets un exemple, comme vous pouvez le voir ici:
Evidemment le formatage à utiliser pour vos commentaires peut dépendre de votre environnement de développement (Visual studio, JavaDoc sous Eclipse, ...)
En ce qui concerne SCE, je suppose que vous entendez par là ce qui suit:
la source
La lisibilité est nécessaire si vous travaillez dans une entreprise et votre code sera lu par quelqu'un d'autre. Si vous écrivez un programme pour vous-même, c'est à vous de décider si vous voulez sacrifier les performances au nom d'un code compréhensible.
la source