ループ内にループを持つことはどの時点でタブーですか?


23

ちょっと興味があるんだけど。Linus Torvaldsからこれを読んだので、私が今までに持っていたほとんどはforループ内のforループでした

タブは8文字であるため、インデントも8文字です。インデント4(または2!)の文字を深くしようとする異端運動があります。これは、PIの値を3に定義しようとすることに似ています。

理論的根拠:インデントの背後にある全体的な考え方は、制御ブロックの開始位置と終了位置を明確に定義することです。特に、20時間連続して画面を見ていると、大きなインデントがある場合にインデントがどのように機能するかを簡単に確認できます。

現在、一部の人々は、8文字のインデントがあると、コードが右に移動しすぎて、80文字の端末画面で読みにくくなると主張します。 その答えは、3レベル以上のインデントが必要な場合、とにかくねじ込まれてしまい、プログラムを修正する必要があるということです。

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

私は、ループの3番目の層に行くことは受け入れられない慣行であり、コードを再構築すると考えました(主にQt)。

Linusは冗談を言っていましたか?

言語やアプリケーションに依存しますか?

3レベル以上のループが絶対に必要なものはありますか?


8
インデントからループのレベルにジャンプする理由がわかりませんか?インデントについて議論する大きな引用があり、そこから突然、ネストされたループに関する質問が続きます。
ピーターB

5
Linusはおそらくそのセクションでは(単なる)冗談ではありませんが、これはスタイルガイドの1つにすぎず、同じスタイルガイドは「カーネルコーディングスタイルは非常にシンプル」、つまり他のスタイルよりも強調していることに注意してください。

5
@Akiva 4つのネストされたループがないと、4次元マトリックスを通過できません。入れ子にできるループの量を誰かが制限するのは正気ではありません。リーナスは明らかに非常に一般的であり、あなたが読んだすべてを聖典とみなすべきではありません。
Alternatex

9
@Alternatex 4つのループが必要であることは、それらが字句的にネストされる必要があることを意味しません。引用文から、実行についてではなく、コードを整理する方法について話していることは明らかです。

4
@delnan 4つのネストされたループが視覚的に楽しいと言っているわけではなく、それについて他の方法があることは知っていますが、OPがLinusの言葉を文字通り取った方法は馬鹿げています。第4レベルのインデント=世界の終わり。休憩してください。
Alternatex

回答:


19

カーネルは単純なアルゴリズムを強く好みます

さまざまなアルゴリズムがループ内で深くネストされたループを必要とする場合がありますが、Linuxカーネルのコンテキストでは(引用されています)、一般に迅速なリアルタイム応答が必要です。そのコンテキストでは、深いネストは、コードフローがこのドメインには複雑すぎることを示している可能性があり、読みやすさやインデントの問題ではなく、実行特性のために変更する必要があることを示す匂いです。

さらに、Linuxカーネルは、監査可能性とテストの要件に関してほとんどのアプリケーションコードとは異なります。したがって、単一の機能に4+レベルのネストされたアルゴリズムを持たないことをお勧めします。可能なすべての制御フローとエッジケースを含め、各コードフラグメントが正確かつ詳細に行うことを確認することは明らかです。深くネストされたコードはそれを妨げます。


Cなどの低レベル言語では、深くネストされたループは一般にbecause、より単純なアルゴリズムに焦点を当てたコーディングスタイルの恩恵を受ける低レベル言語を利用するタブープロジェクトであると思いますか?
アキバ

4
@Akiva低レベルの言語やCなどとは結び付けず、コードのドメインに結び付けます。他のことを犠牲にして堅牢で、セキュリティに焦点を合わせ、監査可能でなければならないコードを記述するとき、同様のガイドラインがどの言語に適用されると思います。たとえば、JavaまたはHaskellで記述された暗号化ライブラリは、できるだけシンプルに保ち、ネストを制限し、あらゆる結果を簡単に分析できるチャンクにすべてを分離しようとするスタイルで記述する必要があります。
ペテルス

非常に洞察に満ちた有用なコメント/回答。ちょっと興味があるんだけど; 低レベルの言語を利用する今日行われているどのようなプロジェクトは、堅牢で監査可能で安全であることに焦点を当てないでしょうか?
アキバ

7
@Akivaは、たとえば、パフォーマンス上の理由でCを使用したいが、制御された条件で内部的に実行されるため、堅牢性やセキュリティについてはあまり気にしない機械学習コードです。また、小さな組み込みマイクロコントローラーにシンプルなビジネス機能を実装します-実際には、品質とセキュリティを犠牲にして機能と開発速度に焦点を当てるようなビジネスがありますが、低レベルの言語を使用します。
ペティス

49

「タブは8文字です」で、ある程度この引用を真剣に受け止めました。タビュレーターの全体的なポイントは、それらが固定数の文字ではないということです(もしあれば、タブは1文字です)。なんという負荷。同様に、「3レベルのインデント」という厳格なルールを設定することは正解であると完全に確信しているわけではありません(に対して厳格なルールを設定することは正気です)。

しかし、インデントのあなたのレベルを制限すること、一般的に合理的な提案ではなく、あなたには驚きとして来るべきもの。

最終的に、プログラムに3つのレベルの反復が必要な場合、それがプログラムに必要なものです。引用の精神は、プロジェクトからその要件を魔法のように軽減することではなく、ロジックを関数や型にまとめて、コードをより簡潔で表現力豊かにすることです。

これは、インデントレベルに関する上記の同じガイドラインにフィードバックするだけです。これは、コードをどのように構成し、読みやすく、保守しやすく、今後数年間変更するのが楽しいかを維持する方法です。


6
タブが8文字であるという「宣言」は、特にカーネル開発のコンテキストにあると考えています。この引用は、特定のプロジェクトのコーディングガイドラインから取られたものであり、一般的な使用のガイドラインとなることを意図したものではないため、十分に意見を述べることが期待されます。
ライライアン

6
@LieRyan:それはまだまだです-何のためのコーディングガイドラインでも、タブを設定する幅を決定するビジネスはありません!しかし、Linusはそれを知っていると思います。
でモニカと

6
そしてもちろんそれは言語に依存します-C#では、名前空間内、クラス内、メソッド内でインデントするのが一般的です。制御フローステートメントの本体について話す前に、すでに3レベルのインデントになっていますインデント。
PeterL

3
@LightnessRacesinOrbit「タブは8文字」のコメントを解釈します。エディターでタブを8ワイドとして個人的に表示する必要があるという意味ではなく、スタイルガイドの他のルールの目的のため(「行の長さの制限80列であり、これが強く推奨される制限です。繰り返しますが、その行の意図は、タブをそのように表示することを強制するものではないと思います。4つのワイドタブでカーネルパッチを適用し、最後にコードをリフローしました。
バリティ

4
@underscore_d:間違っているようです:Outside of comments, documentation and except in Kconfig, spaces are never used for indentation, and the above example is deliberately broken.-OPの引用から6段落下。
スリーブマン

16

ポイントは、フロー制御構造の場合と同じです。コードが理解しにくい場合は、リファクタリングする必要があります。多次元配列の簡単な操作を行う場合、最も内側のループのロジックが単純である限り、5または6の深さでネストされたループを持つことが適切な場合があります。ただし、複雑なビジネスロジックを処理していて、ループの本文が1ダース以上の行である場合は、おそらく、複数のループを深く入れ子にしたくないでしょう。コードの循環的な複雑さを計算してみることができますが、実際に問題になるのは、問題のコードの可読性と保守性です。


11
まさに。Torvaldsがおびただしいことを示唆するのはあまりにも簡単です。(もちろん、彼です。)彼はあなたの好みにはあまりにも硬直しているかもしれませんが、彼は本当の問題を引き起こす本当の開発懸念を説明しています。あなたは彼が言うことを正確に行う必要はありませんが、彼がそれを言っている理由について考える必要があります。
スキャントロジャー

7
@ScantRoger実際、そのトーバルズの引用は、ユーモアのセンスが得られない場合にのみ硬直しすぎます。私が覚えているように、同じ文書の前の方で、彼はGNUコーディングスタイルのガイドラインのコピーを印刷することを提案しますが、それは何らかの儀式で燃やすためだけです。それを真剣に受け止めることはほとんどないでしょうか?この引用では、彼の主なポイントは、Linuxカーネルのインデントを8つのスペースに定義することであり、それ以上でもそれ以下でもありません。最後の文は、そのポイントに下線を引くことのみであり、これ以上のレベルのインデントを使用してはならないことを示すものではありません。
cmaster

1
@cmasterコンテキストをありがとう、すぐに!あなたの質問に答えて、私は何も真剣に受け止めません。;)
スキャントロジャー

2
@cmasterそして、githubプルリクエストへの応答とコミットメッセージの行の長さを読み取ります。彼は完全なナットケースです。
ガスドール

3
GNUコーディングガイドラインを儀式的に燃やすことは実際には必要ないかもしれませんが、いつでも完全に秩序立っています。
dmckee

13

Linusは冗談を言っていましたか?

この作品は遊び心のあるスタイルで書かれており、著者はコーディングスタイルが真剣な実践者の間で議論されている方法に精通していることを示唆しています。私たちは皆好みがあり、少なくとも部分的に頬で舌を使って猛烈に防御しています。私たちはその多くが単なる個人的な好みの問題であることを完全によく理解しています。彼は、非常に多くの言葉で言う"Coding style is very personal, and I won't _force_ my views on anybody"-少なくとも彼が個人的に維持するコードの外で。ただし、特定のプロジェクトのスタイルの一貫性は非常に良い考えです。特定の関数で複数のスタイルを扱うよりも、むしろ嫌いなスタイルにコーディングしたいです。

明らかに遊び心のある文章の例を次に示します。

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

遊び心のある(1)。

3レベルの最大値は双曲的かもしれませんが、インデントが制御不能にならないようにすることは間違いなく良いアドバイスです。カーネルソースをgrepして4つのタブ文字のシーケンスをカウントするつもりはありませんが、Torvaldsが書いたものを少なくとも1つ見つけることができると確信しています。

一方、誰かが頻繁に3レベルのインデントを超えることなくLinuxカーネルを作成できる場合、3レベルの制限は、自分のコードでしばらく試してみる価値のある練習になるかもしれません。これは性転換のようなものではありません。生涯のコミットメントではありません。

もし彼がTorvalds(2)よりもプログラミングをずっとよく理解していると思うインターネット上の誰かに出会ったなら、あなたはどんな人がインターネットで大声で話すのが好きか知っています。

一方、彼は8スペースのタブについては犯罪的に間違っています。それは、拘束され、スロットを介して供給されるべき男性の絶賛です。4つのスペースは明らかに正しいです。

(1)しかし、彼が誤って楕円の前にスペースを置き、その後に2つのスペースを置き、完全に停止した後に2つのスペースを置くことに注意してください。間違っている、間違っている、間違っている。そして、彼は異端者を去勢するための勇敢な胆嚢を持っています。異端者はあなたです、トーバルズ!それはあなたです!

(2)「ソース管理システムの設計方法の理解について話したい場合、議論の余地があるかもしれません。

注:同じ編集を繰り返し送信した親愛なるユーザー:引用された素材のフォーマットは、著者が意図したとおりに正確に保持されます。それは、固定幅テキストの書式設定についてかなりの量の考えを与えた誰かによる、固定幅テキストで書かれた固定幅テキストの書式設定に関するエッセイからだからです。書式設定は、著者の意図の意識的で意図的な部分であり、主題に関連しています。

さらに、私は自分のテキストでその書式設定を参照しました。事前フォーマットを解除すると、脚注(1)が意味不明になります。事前書式設定が削除された場合、脚注(1)のテキストは、文の終わりで完全に停止した後のスペースのペアを参照する必要があります。とにかく、脚注を削除した理由は、それを書いたときよりも面白くなかったためです。しかし、脚注を削除せずに書式設定を削除することは役に立ちません。


3
すばらしい答え。+2 ...に値するケースの1つ(注:.このコメントに間違ったスペースはありません
;

2
あなたが指摘したLinusのイントロの段落は非常に重要なので、それをしてくれてありがとう!私は、最初の文がコンテキストにも非常に重要であると考え、特にpreferred coding styleなどbut this is what goes for anything that I have to be able to maintain
クリス・ハース

9

ライナスは非常に鈍い話すスタイルとユーモアのドライな感覚を持っていますが、この例では彼は冗談を言っていませんでした。アルゴリズムが2レベルよりも深くネストする必要がある状況がありますが、コードをインデントする以外の方法を使用してこれを実現できます。Linuxカーネルスタイルガイドは、深くネストされたループを維持するのが難しいため、これらの他の方法を強く好みます。

代替メソッドのいくつかの例では、再帰を使用したり、内部ループを独自の関数に分割したり、中間データ構造を作成したりできます。

過剰なネストは、記述しやすいが読みにくいケースの1つです。大きなタブの深さを設定することは、Linusが書くのをさらに面倒にする方法です。


3

質問をする人と尋ねない人とでアドバイスが異なる多くの質問があります。「2レベル以上の深さでネストされたループが必要ですか?」あなたが尋ねるなら、それをしないでください。尋ねる必要のない十分な経験がある場合は、それぞれの場合の正しい答えを知っています。そして、あなたは答えがあなたのためではないので、あなたが答えに同意しないかどうか議論しないでください。


1

これは、犬を振る尾の教科書のケースのようです。

80文字のディスプレイを使用している場合は、もちろん、コードに最適な構造が生成されない場合でも、できる限りコードを適合させようとします

ポイントの残りの部分に取り組む:

私はそれが受け入れられない慣行であると考えました。

あなたはこれを読みすぎていると思います。文脈をきちんと理解せずに、読んだものすべてを福音とみなす衝動に抵抗してください。

彼は冗談でしたか?

コンテキストを確認するのは難しいが、上記の私の元のポイントを参照してください。

言語やアプリケーションに依存しますか?

まさにその通り。端末(または端末エミュレータ)でコーディングする可能性のあるメインフレーム/ミッドレンジ言語を使用します。

3レベル以上のループが絶対に必要なものはありますか?

はい、一部のブルートフォースアルゴリズムでは非常に一般的です。Project Eulerの問題31を参照してください。これは、多数のループ(正確には8つ)を使用してブルートフォースで解決できる問題の典型的な例です。


1
問題31はブルートフォースを必要とせず、動的プログラミングアルゴリズムを使用して解決できるようです(編集:つまり、ブルートフォースアルゴリズムを使用している場合、コード構造は最適ではありません)。また、Linusのポイントは、コードが多くのレベルのインデントを必要とする場合、おそらくコードにとって最適な構造ではないということです。
ビンセントサバード

2
@VincentSavard 総当たりが必要だと言ったことはありません。2番目の点に同意しない-場合によっては最も効率的であることは言うまでもなく、最も明確で簡潔なアプローチである場合もあります。
ロビーディー

1
この種の問題では、通常、ループをインデントしません。私は、20のネストされたループを使用した1つのケースがあったと思います。
gnasher729

1
@RobbieDee:私のポイントは、多くのループによって解決される問題の例は、アルゴリズムが動的プログラミングソリューションほど効率的ではなく、インデントのレベルがそれほど必要ないということです。したがって、Linusが言ったように、インデントのレベルは、より良いソリューションを使用して削除できます。また、あなたが言ったことに同意するので、あなたは私の2番目の点を誤解しました。時々、それが最良の解決策です。頻繁ではない場合があり、そうではありません。
ビンセント

1
それは、高速でも単純なことではないだろう、とカーネルの操作は-ライナスの引用はかなり明示的にいくつかのコードは、問題-31は、その後、あなたがとにかくねじ込みしていることをbruteforcingのようなものを必要とする場合と言う必要があり、高速かつ簡単です。カーネルにO(n ^ 4)アルゴリズムを含めると、パフォーマンスまたはサービス拒否の問題の重大なリスクになるため、このコンテキストでは、これは基本的に不適切でありLinuxで望まれるコードの兆候であると警告するだけです。
ペティス

0

Linusは冗談を言っていましたか?

いいえ、それらは公式のガイドラインです。

言語やアプリケーションに依存しますか?

コーディングのガイドラインは一般に言語とアプリケーションに依存しますが、深くネストされたコードは常に読者に負担をかけます。

ネストされたコードの問題は、一般に循環的複雑度が増加することです。つまり、コードがネストされるほど、関数内に潜在的な実行パスが存在します。潜在的な実行パスの組み合わせの爆発により、コードについて推論するのが難しくなるため、一般的に避ける必要があります。

では、なぜ3ですか?主観的なコーディングガイドラインは、強制するのが難しく、自動的に強制することは不可能です。最大レベルのインデントで客観的なコーディングガイドラインを設定するには、数に同意する必要があります。Linuxカーネルでは3を選択しました。

それはarbitrary意的であり、明らかに十分です。

3レベル以上のループが絶対に必要なものはありますか?

ただし、アルゴリズムに関しては、おそらく十分に表現力のある言語では、コードを小さなチャンクに常にリファクタリングできます(関数またはクロージャーを使用して)。

ネストをほとんど行わずに、難読化されたコードを書くことができます。多くの小さな関数は、契約をつづることなく互いに呼び出します...

...ただし、明確な契約を持つ小さな機能は、一般的に明確な契約を持つ大きな機能よりも監査がはるかに簡単です。


2
これは公式のガイドラインかもしれませんが、ガイドラインが実施されていないカーネルコードの場所を見つけるのは簡単です。
MikeB

1
@MikeB:自動的にガイドラインを施行するすべてのより多くの理由...
マシューM.

1
なつみ ガイドラインと必須要件の違いを理解していますか?一般的な「経験則」(必要に応じてガイドライン)として、ガイドラインは推奨に似ており、強制されません。
ブレンダン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.