À quel moment est-il tabou d'avoir des boucles dans les boucles?


23

Juste curieux. Le plus que j'ai jamais eu était une boucle for dans une boucle for, car après avoir lu ceci de Linus Torvalds:

Les onglets sont composés de 8 caractères et les retraits sont donc également composés de 8 caractères. Il y a des mouvements hérétiques qui essaient de faire des indentations de 4 (ou même 2!) Caractères en profondeur, et cela revient à essayer de définir la valeur de PI à 3.

Justification: L'idée derrière l'indentation est de définir clairement où commence et se termine un bloc de contrôle. Surtout lorsque vous regardez votre écran depuis 20 heures d'affilée, vous trouverez beaucoup plus facile de voir comment fonctionne l'indentation si vous avez de grandes indentations.

Maintenant, certaines personnes affirmeront que le fait d'avoir des indentations à 8 caractères fait que le code va trop loin vers la droite et rend la lecture difficile sur un écran de terminal à 80 caractères. La réponse à cela est que si vous avez besoin de plus de 3 niveaux d'indentation, vous êtes quand même foutu et devez corriger votre programme.

https://www.kernel.org/doc/Documentation/CodingStyle

J'ai pensé que c'était une pratique inacceptable pour moi d'aller à une troisième couche de bouclage et de restructurer mon code (principalement Qt).

Linus plaisantait-il?

Cela dépend-il de la langue ou de l'application?

Y a-t-il des choses qui nécessitent absolument trois niveaux de boucle ou plus?


8
Je me demande pourquoi vous passez de l'indentation aux niveaux de boucle? Vous avez une grande citation discutant de l'indentation et tout à coup de cela suit une question sur les boucles imbriquées.
Pieter B

5
Linus ne plaisante probablement pas (seulement) dans cette section, mais notez qu'il ne s'agit que d'un guide de style, et le même guide de style souligne que "le style de codage du noyau est super simple", c'est-à-dire plus que les autres styles.

5
@Akiva Vous ne pouvez pas parcourir une matrice à 4 dimensions sans avoir 4 boucles imbriquées. Je trouve fou que quelqu'un limite la quantité de boucles imbriquées que vous pouvez avoir. Linus était évidemment très général et vous ne devriez pas considérer tout ce que vous lisez comme une Sainte Écriture.
Alternatex

9
@Alternatex Le fait que vous ayez besoin de 4 boucles ne signifie pas qu'elles doivent être imbriquées lexicalement . Il est assez évident d'après la citation que nous parlons de la façon d'organiser le code, pas de l'exécution.

4
@delnan Je ne dis pas que 4 boucles imbriquées sont visuellement agréables et je suis conscient qu'il existe d'autres façons de procéder, mais je trouve idiot comment OP a pris les mots de Linus si littéralement. 4ème niveau d'indentation = fin du monde. Laisse-moi tranquille.
Alternatex

Réponses:


19

Le noyau préfère fortement les algorithmes simples

Bien qu'une variété d'algorithmes puissent nécessiter des boucles profondément imbriquées dans les boucles, dans le contexte du noyau Linux (dans lequel la citation a été dite), vous avez généralement besoin de réponses rapides en temps réel. Dans ce contexte, l'imbrication profonde est une odeur qui peut indiquer que le flux de code est trop complexe pour ce domaine et peut devoir être modifié en raison de ses caractéristiques d'exécution, et non de problèmes de lisibilité ou d'indentation.

De plus, le noyau Linux est différent de la plupart des codes d’application quant aux exigences d’auditabilité et de test - et préférerait donc avoir d'algorithme imbriqué de niveau 4+ dans une seule fonction. Il devrait être évident de voir ce que chaque fragment de code fait exactement et en détail, y compris tous les cas de flux de contrôle et de bord possibles. Un code profondément imbriqué gêne cela.


Pensez-vous donc qu'avec des langages de niveau inférieur tels que C, les boucles profondément imbriquées sont généralement plus de becauseprojets tabous utilisant des langages de niveau inférieur bénéficient d'un style de codage qui se concentre sur des algorithmes plus simples?
Akiva

4
@Akiva Je ne le lierais pas aux langages de niveau inférieur ou C en tant que tel, mais plutôt au domaine du code. Je pense que des directives similaires s'appliqueraient à n'importe quelle langue lors de l'écriture de code qui doit être robuste, axé sur la sécurité et vérifiable au détriment d'autres choses. Par exemple, une bibliothèque de chiffrement écrite en Java ou Haskell doit également être écrite dans un style qui simplifie au maximum les choses, limite l'imbrication et essaie de tout séparer en morceaux qui peuvent être facilement analysés avec toutes leurs conséquences possibles.
Peteris

Un commentaire / réponse très perspicace et utile. Juste curieux; quel type de projet réalisé aujourd'hui qui utilise un langage de bas niveau, ne se concentrerait pas sur la robustesse, l'audit et la sécurité?
Akiva

7
@Akiva par exemple, du code d'apprentissage automatique où vous pouvez utiliser C uniquement pour des raisons de performances, mais ne vous souciez pas beaucoup de la robustesse ou de la sécurité car il sera exécuté en interne dans des conditions contrôlées. En outre, la mise en œuvre de fonctionnalités commerciales simples sur de petits microcontrôleurs intégrés - dans la pratique, cela se concentre souvent sur les fonctionnalités et la vitesse de développement au détriment de la qualité et de la sécurité, mais utilise des langages de bas niveau.
Peteris

49

Dans une certaine mesure, j'ai cessé de prendre cette citation au sérieux dans "Les tabulations sont à 8 caractères" . L'intérêt des tabulateurs est qu'ils ne sont pas un nombre fixe de caractères (si quelque chose, un onglet est un caractère). Quelle charge de tosh. De même, je ne suis pas complètement convaincu que la définition d'une règle stricte et rapide de "trois niveaux d'indentation" soit sensée (autant que la définition d'une règle stricte et rapide pour n'importe quoi est saine).

Cependant, limiter vos niveaux d'indentation est en général une suggestion raisonnable, et non une qui devrait vous surprendre.

En fin de compte, si votre programme a besoin de trois niveaux d'itération, c'est ce dont votre programme a besoin . L'esprit de la citation n'est pas d'alléger comme par magie cette exigence de votre projet, mais de réduire la logique en fonctions et types afin que votre code soit plus tordu et plus expressif.

Cela revient simplement dans la même ligne directrice donnée ci-dessus concernant les niveaux d'indentation. Il s'agit de savoir comment structurer votre code et le garder lisible, maintenable et amusant à modifier pour les années à venir.


6
Je crois que la "déclaration" que les tabulations sont à 8 caractères est spécifiquement dans le contexte du développement du noyau. Cette citation est tirée d'une directive de codage pour un projet spécifique et n'est pas destinée à être une directive d'utilisation générale, et donc elle devrait être assez avisée.
Lie Ryan

6
@LieRyan: Ensuite, c'est encore trop - une directive de codage pour tout n'a rien à faire dictant la largeur de mes onglets! Mais je soupçonne que Linus le sait.
Courses de légèreté avec Monica

6
et bien sûr, cela dépend du langage - en c #, il est courant que vous indentiez à l'intérieur de votre espace de noms, dans votre classe et dans votre méthode .. vous êtes déjà à 3 niveaux d'indentation avant même de parler des corps des instructions de flux de contrôle étant dentelé.
PeterL

3
@LightnessRacesinOrbit J'interprète le commentaire "Les tabulations sont à 8 caractères" pour ne pas signifier que vous devez personnellement afficher les tabulations en tant que 8 de large dans votre éditeur, mais pour les besoins d'autres règles du guide de style (comme "La limite de la longueur des lignes") est de 80 colonnes et c'est une limite fortement préférée. ") on doit traiter les tabulations comme étant 8 colonnes, ceci est également pertinent pour d'autres règles concernant l'alignement des arguments dans les appels de fonction. Encore une fois, je ne pense pas que l'intention de cette ligne vous oblige à afficher les onglets de cette façon, j'ai déjà effectué une correction du noyau avec 4 onglets larges et redistribué le code à la fin.
Vality

4
@underscore_d: Il semble que je me trompe: Outside of comments, documentation and except in Kconfig, spaces are never used for indentation, and the above example is deliberately broken.- 6 paragraphes en dessous de la citation dans le PO.
slebetman

16

Le point est le même que pour toutes les constructions de contrôle de flux: si le code est difficile à comprendre, vous devez le refactoriser. Si vous faites une manipulation simple d'un tableau multidimensionnel, alors avoir des boucles imbriquées à cinq ou six profondeurs peut être approprié, tant que la logique dans la boucle la plus intérieure est simple. Cependant, si vous traitez une logique métier compliquée et que le corps de votre boucle est composé d'une douzaine de lignes ou plus, vous ne voudrez probablement pas imbriquer plus d'une boucle en profondeur. Vous pouvez essayer de calculer la complexité cyclomatique du code, mais ce qui se résume vraiment à la lisibilité et à la maintenabilité du code en question.


11
Exactement. Il est trop facile de suggérer que Torvalds est un huard. (Il l'est, bien sûr.) Il peut être trop rigide à votre goût, mais il décrit un réel problème de développement qui pose de vrais problèmes. Vous n'êtes pas obligé de faire exactement ce qu'il dit, mais vous devriez vous demander pourquoi il le dit.
Scant Roger

7
@ScantRoger En fait, cette citation de Torvalds ne semble que trop rigide si vous n'avez pas son sens de l'humour. Comme je me souviens, plus tôt dans le même document, il suggère d'imprimer une copie des directives de style de codage GNU, seulement pour les graver dans une sorte de cérémonie. Vous prendrez à peine cela au sérieux, n'est-ce pas? Dans cette citation, son point principal est de définir l'indentation pour que le noyau linux soit huit espaces, rien de plus, et rien de moins, c'est de cela qu'il est rigide. La dernière phrase ne sert qu'à souligner ce point, sans dire que vous ne devez pas utiliser plus de niveaux d'indentation - aucune rigidité implicite.
cmaster

1
@cmaster Merci pour le contexte, tout de suite! En réponse à votre question, je ne prends pratiquement rien au sérieux. ;)
Scant Roger

2
@cmaster puis on lit ses réponses aux requêtes pull github et la longueur de ligne des messages de commit. C'est un casse-noisette total.
Gusdor

3
Graver cérémonieusement les directives de codage GNU n'est peut-être pas réellement nécessaire, mais il est tout à fait en ordre à tout moment.
dmckee

13

Linus plaisantait-il?

La pièce est écrite dans un style ludique qui suggère que l'auteur est familier avec la façon dont le style de codage est discuté parmi les pratiquants sérieux: nous avons tous nos préférences et nous les défendons avec rage, mais avec la langue au moins partiellement en joue. Nous comprenons très bien qu'une grande partie est juste une question de goût personnel. Il dit, en tant de mots,"Coding style is very personal, and I won't _force_ my views on anybody" - du moins en dehors du code qu'il maintient personnellement. Mais la cohérence du style dans un projet donné est une très bonne idée. Je préfère de beaucoup coder un style que je n'aime pas plutôt que de traiter plusieurs styles dans une fonction donnée.

Voici un exemple d'écriture clairement ludique:

However, there is one special case, namely functions: they have the
opening brace at the beginning of the next line, thus:

int function(int x)
{
    body of function
}

Heretic people all over the world have claimed that this inconsistency
is ...  well ...  inconsistent, but all right-thinking people know that
(a) K&R are _right_ and (b) K&R are right.  Besides, functions are
special anyway (you can't nest them in C).

Ludique (1).

C'est sans doute un bon conseil pour essayer de ne pas perdre le contrôle, bien qu'un maximum de trois niveaux puisse être hyperbolique. Je ne vais pas chercher la source du noyau et compter les séquences de quatre caractères de tabulation, mais je parie que vous pourriez en trouver au moins un que Torvalds a écrit.

D'un autre côté, si quelqu'un peut écrire le noyau Linux sans souvent dépasser trois niveaux d'indentation, une limite à trois niveaux pourrait être un exercice à essayer pendant un certain temps dans votre propre code, juste pour voir où cela vous mène. Ce n'est pas comme un changement de sexe, tu sais. Ce n'est pas un engagement à vie.

Si vous rencontrez quelqu'un sur Internet qui pense qu'il comprend beaucoup mieux la programmation que Torvalds (2), eh bien, vous savez quel genre de gens aiment parler gros sur Internet.

D'un autre côté, il se trompe criminellement au sujet des onglets de huit espaces. C'est le délire d'un homme qui devrait être maintenu en retenue et nourri par une fente. Quatre espaces est évidemment correct.

(1) Mais notez comment il place par erreur un espace avant les ellipses, et deux espaces après eux, et deux espaces après un point. MAUVAIS, MAUVAIS, MAUVAIS. Et puis il a le culot effronté de fustiger les hérétiques. L'hérétique, c'est toi, Torvalds! C'EST TOI!

(2) Si vous voulez parler de " comprendre comment concevoir un système de contrôle des sources ", il pourrait y avoir une place pour le débat.

Remarque: Cher utilisateur qui a soumis à plusieurs reprises la même modification: la mise en forme dans le matériel cité est conservée exactement comme l'auteur voulait qu'elle soit. C'est parce que c'est à partir d'un essai sur la mise en forme du texte à largeur fixe, écrit en texte à largeur fixe, par quelqu'un qui a donné une bonne idée de la mise en forme du texte à largeur fixe. La mise en forme est une partie consciente et délibérée de l'intention de l'auteur, et elle est pertinente pour le sujet.

De plus, j'ai fait référence à cette mise en forme dans mon propre texte. Si vous supprimez le pré-formatage, ma note de bas de page (1) devient du charabia. Si la pré-mise en forme est supprimée, le texte de ma note de bas de page (1) devrait faire référence aux paires d'espaces après les arrêts complets à la fin des phrases. Je peux quand même voir une justification pour supprimer cette note de bas de page, car elle est moins drôle qu'elle ne semblait quand je l'ai écrite. Mais supprimer le formatage sans supprimer la note de bas de page est inutile.


3
Magnifique réponse. Un des cas qui mériterait un +2 ... (Remarque: pas de mauvais espaces autour .dans ce commentaire ;-))
cmaster

2
Le paragraphe d'introduction de Linus que vous avez souligné est très important, alors merci de le faire! Je pense que la première phrase est également très importante pour le contexte, en particulier preferred coding styleainsi quebut this is what goes for anything that I have to be able to maintain
Chris Haas

9

Linus a un style de parole très franc et un sens de l'humour sec, mais il ne plaisantait pas dans ce cas. Il existe des situations où un algorithme doit être imbriqué plus profondément que deux niveaux, mais vous pouvez accomplir cela en utilisant d'autres moyens que d'indenter votre code. Le guide de style du noyau Linux préfère fortement ces autres méthodes, en raison de la difficulté de maintenir des boucles profondément imbriquées, et c'est ce que Linus dit ici.

Pour certains exemples de méthodes alternatives, vous pouvez utiliser la récursivité, diviser les boucles internes en leurs propres fonctions ou créer des structures de données intermédiaires.

L'imbrication excessive est l'un de ces cas qui est plus facile à écrire, mais plus difficile à lire. La définition d'une grande profondeur de tabulation est la manière de Linus de rendre plus ennuyeux d'écrire aussi.


3

Il y a beaucoup de questions où le conseil est différent pour quelqu'un qui pose la question que pour quelqu'un qui ne pose pas. Si vous demandez «Si jamais j'ai des boucles imbriquées à plus de deux niveaux de profondeur», alors pour vous, la personne qui pose cette question, la réponse est NON. Si vous demandez, alors ne le faites pas. Si vous avez suffisamment d'expérience que vous n'avez pas besoin de demander, alors vous savez quelle est la bonne réponse dans chaque cas. Et ne discutez pas si vous n'êtes pas d'accord avec la réponse, car la réponse n'est pas pour vous.


1

Il semblerait que ce soit un cas d'école où la queue remue le chien.

Si vous avez un affichage de 80 caractères , vous allez bien sûr essayer d’adapter le code du mieux possible, même s’il ne produit pas la meilleure structure pour le code .

S'attaquer au reste de vos points de front:

J'ai pensé que c'était une pratique inacceptable.

Je pense que vous en lisez trop. Résistez à l'envie de prendre tout ce que vous lisez comme évangile sans bien comprendre le contexte.

Plaisantait-il?

Difficile de déterminer le contexte, mais voir mon point d'origine ci-dessus.

Cela dépend-il de la langue ou de l'application?

Tout à fait. Prenez n'importe quelle langue mainframe / milieu de gamme où vous êtes susceptible de coder sur un terminal (ou un émulateur de terminal).

Y a-t-il des choses qui nécessitent absolument trois niveaux de boucle ou plus?

Oui, c'est très courant dans certains algorithmes de force brute. Voir le problème 31 sur Project Euler. Ceci est un exemple classique d'un problème qui pourrait être résolu avec la force brute en utilisant un certain nombre de boucles (8 pour être exact).


1
Il semble que le problème 31 ne nécessite pas de bruteforce et pourrait être résolu en utilisant un algorithme de programmation dynamique (edit: ce qui signifie que votre structure de code n'est pas la meilleure si vous utilisez un algorithme de bruteforce). En outre, le point de Linus est que si votre code nécessite de nombreux niveaux d'indentation, ce n'est probablement pas la meilleure structure pour le code.
Vincent Savard du

2
@VincentSavard Jamais dit qu'il fallait de la force brute. En désaccord avec votre 2e point - c'est parfois l'approche la plus claire et la plus succincte, sans parler de la plus efficace dans certains cas.
Robbie Dee

1
Avec ce genre de problème, je n'indente généralement pas les boucles. Je pense que j'avais un cas avec 20 boucles imbriquées, absolument trivial à écrire, et aucune indentation pour que vous puissiez voir que les boucles étaient presque identiques.
gnasher729

1
@RobbieDee: Mon point est que votre exemple d'un problème résolu par de nombreuses boucles est que votre algorithme n'est pas aussi efficace qu'une solution de programmation dynamique, qui ne nécessite pas autant de niveaux d'indentation. Ainsi, comme l'a dit Linus, vos niveaux d'indentation peuvent être supprimés en utilisant une meilleure solution. Vous avez également mal compris mon deuxième point car je suis d'accord avec ce que vous avez dit. Parfois , c'est la meilleure solution. Parfois, ce n'est pas souvent et ce n'est pas probable.
Vincent Savard

1
La citation de Linus dit à peu près explicitement que si du code nécessite quelque chose comme le renforcement brutal de ce problème-31, alors vous êtes foutu de toute façon - ce ne sera pas rapide ni simple, et les opérations du noyau doivent être rapides et simples. L'inclusion de tout algorithme O (n ^ 4) dans le noyau est un risque important de problèmes de performances ou de déni de service, donc dans ce contexte, la recommandation avertit simplement qu'il s'agit d'un signe de code qui peut être fondamentalement inapproprié et souhaité sous Linux.
Peteris

0

Linus plaisantait-il?

Non, ce sont les directives officielles.

Cela dépend-il de la langue ou de l'application?

Les directives de codage dépendent généralement de la langue et de l'application, mais le code profondément imbriqué impose toujours des taxes au lecteur.

Le problème avec le code imbriqué est qu'en général il augmente la complexité cyclomatique: c'est-à-dire que plus le code est imbriqué, plus il existe de chemins d'exécution potentiels dans la fonction. Une explosion combinatoire de chemins d'exécution potentiels rend difficile la réflexion sur le code, et doit donc être évitée en général.

Alors pourquoi 3? Une directive de codage subjective est à la fois difficile à appliquer et impossible à appliquer automatiquement. Mettre en place une ligne directrice de codage objectif sur le niveau maximal d'indentation nécessite de s'entendre sur un nombre: dans le noyau Linux, ils ont choisi 3.

C'est arbitraire, et apparemment suffisant pour eux.

Y a-t-il des choses qui nécessitent absolument trois niveaux de boucle ou plus?

Sur le plan de l'algorithme, probablement, mais dans des langages suffisamment expressifs, vous pouvez toujours refactoriser le code en petits morceaux (que ce soit avec des fonctions ou des fermetures).

Vous pouvez évidemment écrire du code obscurci avec peu d'imbrication et beaucoup de petites fonctions qui s'appellent sans jamais épeler leur contrat ...

... cependant, les petites fonctions avec des contrats clairs sont beaucoup plus faciles à contrôler que les grandes fonctions avec des contrats clairs en général.


2
Bien que cela puisse être la directive officielle, il est trivial de trouver des endroits dans le code du noyau où la directive n'est pas appliquée.
MikeB du

1
@MikeB: Raisons de plus pour appliquer automatiquement les directives ...
Matthieu M.

1
@MatthieuM. Êtes-vous sûr de comprendre la différence entre les lignes directrices et les exigences obligatoires? En tant que «règle générale» (une ligne directrice si vous le souhaitez), les lignes directrices ressemblent davantage à des recommandations et ne sont pas appliquées.
Brendan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.