字下げスタイル
字下げスタイルまたはインデントスタイル(英: indent style)とは、プログラミングにおいてプログラムの構造を明らかにするために、コードのブロックの字下げをどうするかを決めたものである。本項ではC言語やそれに類似した言語を主に扱うが、他のプログラミング言語(特に括弧を使用してブロックを記述する言語)にも適用可能である。字下げスタイルはプログラミング作法の一部である。
概要編集
字下げは大半のプログラミング言語では必須ではない。むしろ、プログラマは他の読者、あるいは自分自身にプログラムの構造を見やすく伝えるために字下げを行う。特に字下げは、条件分岐やループといった制御構造を明示するために使われる。しかし、一部の言語(PythonやOccam)では、括弧やキーワードではなく字下げで構造を記述するようになっている(オフサイドルール)。
字下げの大きさもスタイルによって様々である。多くの初期のプログラムは字下げにタブ文字を使っていた。これは、単純であり、ソースファイルの大きさを無駄に大きくしないという利点があった。しかし同時に、定義が異なる環境でソースファイルをやり取りすると混乱が生じることがあった。例えば、UNIXのエディタでのタブ文字の長さが一般に空白文字8個分である一方、macOSでは4文字分である。そのため、最近のプログラミング向けエディタでは任意のサイズの字下げが可能で、空白文字とタブ文字を適当に混在させられることが多い。また、字下げをそもそも空白文字のみで行うこともある。
字下げスタイルやタブ文字の長さを自動的に調節するプログラムも存在する。例えば、UNIX系オペレーティングシステムによく搭載されているプログラムとして indent
がある。このようなプログラムは、その作者が一般的と考えた字下げスタイルが自分の字下げスタイルに合っている場合には有効であるが、自分の字下げスタイルと違っている場合には余計に不満が出てくる場合もある。
K&Rのスタイル編集
K&Rスタイル (あるいは、カーネルスタイル)とは、ブライアン・カーニハンとデニス・リッチーの著書でK&Rこと『プログラミング言語C』で使われた字下げスタイルであり、C言語で一般に使われている。C11 の仕様書 ISO/IEC 9899:2011 のサンプル、UNIXカーネル、Linuxカーネルはこのスタイルでソースコードが書かれている。Objective-C、C++ などでは、それほど一般的ではない。このスタイルでは、ブロック開始の中括弧を制御文と同じ行に置き、ブロック内の文を字下げして記し、ブロックを閉じる中括弧を制御文と同じ字下げ位置に戻して記す(その行は中括弧が先頭になる)。関数はそれとは異なり、関数の定義の最初の中括弧は宣言の次の行の先頭に記され、宣言と同じ字下げレベルとなる(これは次の例で示すように、ANSI標準より前の構文のせいでもある(K&Rの初版の中のコードはこのような構文で書かれていた)。行頭の中括弧で関数本体の先頭を検出しているツール等があったため、標準化後や他のスタイルのコードでもここだけは同じにしていることも多い)。
int main(argc, argv)
int argc;
char *argv[];
{
...
while (x == y) {
something();
somethingelse();
if (some_error)
do_correct();
else
continue_as_usual();
}
finalthing();
...
}
このスタイルの支持者はこれを "The One True Brace Style"(1TBS あるいは OTBS)と呼ぶ。
このスタイルの支持者によれば、ブロック開始の中括弧は新たな行に置く必要はなく、最後の中括弧は概念的に対応する文と同じ位置まで上げるのだという。このスタイルの欠点は、ブロックの最後の中括弧が行を新たに必要とする点であるが、if/else や do/while ではこれが部分的に改善される。
if (x < 0) {
printf("Negative");
negative(x);
} else {
printf("Positive");
positive(x);
}
このスタイルのソースコードはブロック開始の中括弧を探すのが困難と言われるが、字下げが始まった位置は見れば明らかなので、その上の行の最後に中括弧があることは明らかである。
このスタイルができた当時、端末の行数はわずか24行であったため、ブロック開始の中括弧に1行を割くことで見える範囲が狭まることを嫌ったと考えられる。上の例でも明らかなように、if...else if...[etc.]...else といったコードでは、中括弧ごとに新たな行を消費するよりも多くの内容が少ない行数で表示できる。
『プログラミング言語C』は、プログラミングにこのスタイルを推奨しているわけではない。次で述べるように、スタイルを選んだら一貫して使うように、とのみ述べている。単に同書に印刷されているプログラムリストがこのスタイルであるというだけであり、書籍としてのレイアウト上の都合による点がある(特に波括弧の手前に改行を入れない点など)とも言われる[1]。
同書自身による注意をここに引用する:
中括弧の位置はあまり重要ではないが、それに信念を持っている人々も多い。我々はある一般的なスタイルを選択した。あなたは自分に合ったスタイルを選んで、一貫してそれを使えばよい。 — Brian W. Kernighan and Dennis M. Ritchie、プログラミング言語C
これは字下げスタイルにこだわる人々への戒めでもある。著者の1人デニス・リッチーはC言語の設計開発者でもあるが、彼がこの字下げスタイルの支持者というわけでもない。
アップルのXcodeはこのスタイルをデフォルトで使っている。
Java/ECMAScript編集
Java言語ではサン・マイクロシステムズが1995年(最終改訂は1999年4月20日)に発表した公式のコーディング規約「Code Conventions for the Java Programming Language」[2]に沿って書かれることが多い。これは、K&Rスタイルをベースに、クラス定義やメソッド定義の最初の中括弧を次の行に置いたりしない物である。また、ActionScriptやJavaScriptといったECMAScript派生言語でも一般的にJava言語コーディング規約に類似した書き方がされることが多い。
class Test {
public static void main(String[] args) {
if (args.length > 0) {
} else {
}
}
}
BSD/オールマンのスタイル編集
BSD/オールマン・スタイル (Allman style) もよく使われる。これはエリック・オールマンの名が由来である。このスタイルでは、制御文の後の中括弧を次の行に置き、制御文と同じ字下げ位置とする。ブロック内の文は次のレベルに字下げされる。
while (x == y)
{
something();
somethingelse();
}
finalthing();
これはPascalやTransact-SQLの標準的な字下げに似ていて、中括弧が "begin" や "end" といったキーワードと同じように扱われている。
このスタイルの利点は、ブロックの前後が中括弧しかないほとんど空白の行で囲まれているため、非常にわかりやすい点である。また、対応する中括弧が同じ字下げ位置に必ず来るので、その対応も目で追いやすい。
欠点は、中括弧ごとに行を消費してしまう点である。例えば、24行しか表示できない端末でソースを表示することが多いならこれは問題だが、表示範囲が大きければあまり問題とはならない。
より深刻な欠点は、例えばwhile文がセミコロンで終わっているような(下記参照)特殊なコーディングで制御構造を見誤る危険性がある点である。これは深刻なバグの元となる危険がある。下記の例では、x == y のときプログラムがハングアップするので、テストすればすぐにバグが明らかとなる。しかし、if文やfor文ではこのような問題にはなかなか気づかないことがある。
while (x == y);
{
something();
somethingelse();
}
finalthing();
このスタイルは、制御文とブロックを分離することで可読性を向上させることを目的としており、一度に表示できるコードの量は二の次となっている。
Microsoft Visual Studio(Microsoft Visual C++)は、このスタイルをデフォルトで使っている。
C#編集
C#言語について、マイクロソフトは「C# のコーディング規則」[3]を公開しており、このレイアウト規則はBSD/オールマンのスタイルに基づいている。
if ((val1 > val2) && (val1 > val3))
{
something();
}
BSD/KNFスタイル編集
Kernel Normal Form とも呼ばれるスタイルで、BSD系オペレーティングシステムでよく使われている。主にカーネルコードで使われているが、ユーザーランドのコードでもよく使われている。
ハードタブ(viでは ts)は一般に8文字ぶんの幅だが、ソフトタブはその補助として定義され(vi では sw)、通常4文字幅とされている。
ハードタブはブロックを示すのに使われ、ソフトタブは文が1行に収まらずに折り返さなければならないときに使われる。
さらに言えば、関数呼び出しでは括弧の前に空白を置かないが、C言語の構文 if、while、do、switch、return は括弧の前に空白を置く(return 文で値を返すとき括弧を使用)。
以下はその例である:
while (x == y) {
something();
somethingelse();
}
finalthing();
if (data != NULL && res > 0) {
if (!JS_DefineProperty(cx, o, "data", STRING_TO_JSVAL(
JS_NewStringCopyN(cx, data, res)), NULL, NULL,
JSPROP_ENUMERATE)) {
QUEUE_EXCEPTION("Internal error!");
goto err;
}
PQfreemem(data);
} else {
if (!JS_DefineProperty(cx, o, "data", OBJECT_TO_JSVAL(NULL),
NULL, NULL, JSPROP_ENUMERATE)) {
QUEUE_EXCEPTION("Internal error!");
goto err;
}
}
static JSBool
pgresult_constructor(JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval)
{
QUEUE_EXCEPTION("PGresult class not user-instanciable");
return JS_FALSE;
}
ホワイトスミスのスタイル編集
ホワイトスミス・スタイルは上述の3例に比較するとあまり有名ではない。このスタイルでは制御文の後の中括弧を次の行に置くが、このときに字下げする。ブロック内の文は中括弧と同じ字下げレベルに書かれる。
while (x == y)
{
something();
somethingelse();
}
finalthing();
このスタイルの利点はBSD/オールマン・スタイルと同じで、ブロックと制御文が明確に分離される点である。また、中括弧とその中の文を同じ字下げレベルにすることで概念的にこれらが1つの文と同じであることを強調する。さらに、中括弧が文法的には while 文などの一部ではなく、複合文の一部であることも強調している。
欠点は中括弧が目立たない点である。ただし、中括弧だけで1つの行となっているため、目立つか目立たないかは意見の分かれるところでもある。
GNUスタイル編集
BSD/オールマンやホワイトスミス・スタイルと同様、GNUスタイルでも中括弧だけで行を構成する。中括弧は空白2個ぶん字下げされ、その中の文はさらに空白2個ぶん字下げされる。リチャード・ストールマンが広めたスタイルであり、LISPのコードを書いた経験がベースにあると考えられる。字下げとは直接関係ないが、GNUスタイルでは関数呼び出しの括弧の前にも空白を置く。
while (x == y)
{
something ();
somethingelse ();
}
finalthing ();
利点はBSD/オールマンやホワイトスミスと同様で、かつホワイトスミスの欠点とされた「中括弧が目立たない」という問題にも対処している。
GNU EmacsエディタやGNUのindentコマンドでは、デフォルトでこのスタイルでの字下げを行う。GNU関係者はほぼ全てこのスタイルを使っているが、GNU以外でも一部で使われている。
GNU Emacs を使わない場合や、類似のカスタマイズ可能なエディタを使えない場合、エディタによる自動字下げではこのスタイルはなかなか対応できない。
Picoスタイル編集
Picoという言語で、その開発者も一般に使っているスタイルは、これまでに説明したどのスタイルとも異なっている。Pico には return 文がなく、文の終わりを示す記号としてではなく文と文の分離記号としてセミコロンが使われていることから、次のようなスタイルが生まれた:
stuff(n):
{ x: 3 * n;
y: doStuff(x);
y + x }
その利点と欠点は、画面表示量を重視するK&Rスタイルに近い。また、どちらの中括弧も独立した行になっていないという点でK&Rスタイルよりも一貫性があるとも言える。
Bannerスタイル編集
bannerスタイルは、ブロックのヘッダ部だけを字下げレベルで特別に目立たせるスタイルである。ちょうど、K&Rスタイルでブロックの終わりの中括弧の字下げレベルを戻さないスタイルである。
function1 () {
dostuff
do more stuff
}
function2 () {
etc
}
マークアップ言語では次のようになる。
<table>
<tr>
<td> lots of stuff...
more stuff
</td>
<td> alternate for short lines </td>
<td> etc. </td>
</tr>
</table>
<table>
<tr ... etc>
</table>
さらに、終わりの中括弧を別の行にしない書き方もある。このスタイルでは中括弧はブロックの識別の役に立たないが、情報のない行を省くという利点もある。
for(i = 0; i < 10; i++) {
if(i % 2 == 0) {
doSomething(i); }
else {
doSomethingElse(i); } }
その他編集
ある状況では、ブロックの境界を見失う危険性が生じる。制御構造が複雑で何重にも入れ子になっているときに起きやすい。そのようなコードをスクロールしながら見ていて、制御構造のつながり方を見失うのである。
始まりの中括弧を数えることで制御構造を確認する場合、K&Rなどのスタイルでは、制御構造と中括弧が見た目で分離されていないため、問題が発生しやすい。字下げレベルを手掛かりとする場合は、K&Rスタイルなどの方がブロックを表示する行数が少なくなるため、可読性が増す。
for文などで制御構造を見失うのを防ぐため、ハードタブの8文字幅などの大きな字下げを使ったり、大きな関数をもっと読みやすい小さな関数に分割したりする。Linux ではK&Rスタイルに加えて、そのような手法を使用している。
別の方法として、閉じる側の中括弧の行に以下のようなコメントを加える:
for ( int i = 0 ; i < total ; i++ ) {
foo(bar);
} //for ( i )
if (x < 0) {
bar(foo);
} //if (x < 0)
しかし、この方法では同じコードをソース内の2ヶ所に記述しているため、修正を行う際に問題となる。
折りたたみ機能のあるエディタを使うという手法もあり、ある字下げレベル以降のブロックを隠して表示するなどの機能が使える。
参考文献編集
脚注編集
- ^ 日本語版ではそうなっていないが、同書の原書はレイアウトに気が配られている。
- ^ Code Conventions for the Java Programming Language: Contents
- ^ C# のコーディング規則 - C# プログラミング ガイド | Microsoft Docs