forループでセミコロンとコンマが交換されるのはなぜですか?


49

多くの言語(CからJavaScriptまでの幅広いリスト):

  • ,引数をコンマで区切る(例func(a, b, c)
  • セミコロンで;区切られた順次命令(例instruction1; instruction2; instruction3)。

したがって、同じ言語のforループでこのマッピングが逆になっているのはなぜですか

for ( init1, init2; condition; inc1, inc2 )
{
    instruction1;
    instruction2;
}

代わりに(私にとってより自然に見えるもの)

for ( init1; init2, condition, inc1; inc2 )
{
    instruction1;
    instruction2;
}

確かに、for(通常は)関数ではなく、引数(すなわちinitconditionincrement)より、関数の引数のような一連の命令よりも動作します。

それは歴史的な理由/慣習によるものですか、それともループの交換,;ループの良い根拠がありますか?


1
(ここに私の最初の投稿。この質問がプログラマーに属するのかSOに属するのかわからないので、必要に応じて自由に移行してください。)
Piotr Migdal

8
これは間違いなくプログラマーの投稿です。ようこそ!:-)
Martijn Pieters

1
「Why Not」は同じ答えを持つことで答えを提供します-「誰かが選択をする必要があり、それが彼らが行った選択だから」「「{」と「}」を選択した理由と他の1000の選択と同じ彼らが作った-「理由」
mattnz

2
@mattnz問題は、一貫性(「なぜ使用し;ないの|か」ではない(または「その他」ではなく「その他」を使用するのはなぜか)ではない)です。これは1つの言語ではなく、多数の言語です。例えば、「whileループの短縮形としてCで作成され(また、incの複数のステートメントは後で考えられた)、プログラマーの苛立ちを避けるために人々はそれを変更したくなかった」という答えはまったく問題ありません。
ピョートルミグダル

私は、おそらくK&R で、forステートメントのinit-expressionで複数の変数を初期化できるようにするためにカンマ演算子が元々言語追加されたことを思い出しました。
zwol

回答:


18

したがって、同じ言語でforループのマッピングが逆になっているのはなぜですか。

技術的には、マッピングは「逆」ではありません。

  • コンマで区切られたものはパラメーターではありません。(少なくとも)C ++およびJavaでは、宣言にできるため、式ではありません。
  • セミコロンで区切られたものも(単一の)ステートメントではありません。

実際には、同じシンボルが異なる方法で使用されている異なる構文コンテキストがあります。likeとlikeを比較していないので、マッピングはなく、セマンティックの一貫性に基づいた一貫したマッピングに対する強力な議論はありません。

それでは、なぜ逆にしないのですか?

理由は、との「自然な」意味にある,と思います;。英語の記述言語では、セミコロンはコンマよりも「強い」区切りであり、セミコロンのグリフはコンマよりも見やすくなっています。これら2つのことが組み合わさって、現在の配置が(私には!)より自然に見えるようになります。

しかし、構文の選択が行われた理由を確実に知る唯一の方法は、Cデザイナーが1970年までに考えていたことを教えてくれることです。私は彼らがはるか昔になされた技術的決定の明確な記憶を持っているとは思わない。


歴史的な理由/慣習によるものですか

「for」ループにCに似た構文を使用したC以前の言語は知りません。

  • Donal Fellowsは、BCPLとBには同等の構造がないことを指摘しています。

  • FORTRAN、COBOL、およびAlgol-60(およびPascal)の同等物は表現力が低く、Cの「for」構文に似ていない構文がありました。

しかし、C、C ++、JavaのようなCの後の言語はすべて、Cから「for」構文を明確に借用しています


したがって、(,vs ;)の哲学は(タプルvsシーケンススプリッター)ではなく(弱いvs強いブレーク)ですよね?それでも私にとっては、引数またはステートメントがより強いブレークを必要とするかどうかは明らかではありません(ステートメントのシーケンスの多くの場合、ブレークは暗黙的です(たとえばJavaScript(egを参照i++[line break]j++))) 「明らかに逆」ではありません。
ピョートルミグダル

@PiotrMigdalコンマを区切り文字として使用すると、コンマオペランドの使用が妨げられ、forループのコンポーネントが式ではなくステートメントであることを意味する場合があります。これには大きな意味があります。

最後のコメントは、BCPLが何をしたのか興味がありましたが、明らかにそこFOR i = e1 TO e2 BY e3 DO c(e1..e3の式、cコマンド)があり、これはBASICの構文により似ています。ソース
からCVn

1
@PiotrMigdal-「哲学」は、K&Rが1970年に考えていたものは何でもです。あなたが想像するほど深く考えたとは思いません。(アセンブラーで大量の電話交換ソフトウェアを記述する必要を避けるために、「高レベル」言語を実装しようとしていました。)
Stephen C

確認しました。for構文は(それがでなかったCで導入されたB又はBCPL)。
ドナルドフェローズ

60

次のようなループを作成します。

 for(x = 0; x < 10; x++)

言語は、ループが次のように見えるように定義されている可能性があります。

 for(x = 0, x < 10, x++)

ただし、whileループを使用して実装された同じループを考えてください。

 x = 0;
 while(x < 10)
 {
     x++;
 }

x=0and x++は文であり、セミコロンで終わることに注意してください。関数呼び出しで使用するような式ではありません。セミコロンはステートメントを区切るために使用され、forループの3つの要素のうち2つはステートメントであるため、そこで使用されます。forループは、このようなwhileループの単なるショートカットです。

さらに、引数は実際には関数の引数のようには機能しません。2番目と3番目は繰り返し評価されます。シーケンスではないのは事実ですが、関数の引数でもありません。

また、コンマを使用してforループに複数のステートメントを含めることができるという事実は、実際にはforループ外で実行できることです。

x = 0, y= 3;

forループ外でも完全に有効なステートメントです。ただし、forループ以外での実用的な使い方は知りません。しかし、ポイントは、コンマが常にステートメントを細分化することです。forループの特別な機能ではありません。


確かに、「while」ループは「より基本的」であることを理解しています。しかし、このような「速記法」は(少なくとも私にとっては)あまり意味がありません。これはx = 0; y = 0;、(中括弧内)で始まる可能性があるためx++; y++;です...
Piotr Migdal

2
@PiotrMigdal、ああ、できます。私のポイントがループの内側片(コンマで区切られている)(セミコロンで区切られている)ステートメントではない式であるということである
ウィンストン・エバート

1
私は違いを得る、私にとって;一連のステートメントにとっては自然であり、必ずしもすべてのステートメントを分離するわけではありません(それは味が違うだけですか?)そして、現在の大会の一つに時折分離で終わるステートメントのシーケンス ...とにかくカンマで
ピョートルMigdal

3
@PiotrMigdal、構造体/共用体のメンバーはセミコロンで区切られていますが、実際にはシーケンシャルではありません。したがって、その使用における一連のステートメントに限定されないことは確かです。結局のところ、構文はむしろ好みに合わせて決定されます。
ウィンストンイーバート

しかし、forループ以外の実用的な使い方は知りません---どうですか(foo)?bar++, qux++:bletch--- ?:式に1つだけでなく2つのことをさせたい場合。もし戻り値がfootrueであるquxが、両方barquxインクリメントます。

15

CおよびC ++では、これは単なるカンマではなく、カンマ演算子です。

forループの文法は次のようなものです

for ([pre-expression]; [terminate-condition]; [increment-expression]) body-expression

ご質問の場合:

pre-expression -> init1, init2
terminate-condition -> condition
increment-expression -> inc1, inc2

コンマ演算子を使用すると、1つのステートメントで複数のアクションを実行できることに注意してください(コンパイラーが見るとおり)。あなたの提案が実装された場合、プログラマがコンマ演算子ステートメントまたはセパレータを書くことをいつ意図したかに関して、文法にあいまいさがあります。

要するに、;文の終わりを意味します。forループが囲まれ、オプションの文のリストが続くキーワードです()。コンマ演算子ステートメントを使用すると,、単一のステートメントで使用できます。


3
forループは、セミコロンで区切られた一連の式です。ステートメントは式よりもはるかに多くの場合があります。caseステートメントやifステートメントをforループ部分に入れることはできません。forループのコンポーネントは文があると言って重要な意味合いであるときに1人のルックスのループのためのBNF形式

@MichaelT:ただし、C ++では、forループの構文では、ステートメント(宣言)を最初の部分として明示的に許可しています。(C ++は、その前身であるC89とは対照的に、関数中の宣言を許可していました)。CやC ++に近い2つの言語であっても、そのようなステートメントを言語間で一般化することはできません。
MSalters

@MichaelT「のようなもの」の部分を見逃しましたか?
ジェームズ

あなたは、実際のBNF使用して「のようなもの」を避けることができ@James for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>のためのCfor ( for-init-statement; conditionopt ; expressionopt ) statementのためのC ++を ---「;」ステートメントターミネータを示すだけではありません。forループの後に()で囲まれたステートメントが続きません。

8

概念的な反転はありません。

Cのセミコロンは、コンマよりも主要な区分を表します。それらはステートメントと宣言を分離します。

forループの主な区分は、3つの式(または宣言と2つの式)と1つの本文があることです。

Cのforループに表示されるコンマは、forループの構文の一部ではありません。それらはコンマ演算子の単なる現れです。

コンマは、関数呼び出しの引数間および関数宣言のパラメーター間の主要な区切り記号ですが、セミコロンは使用されません。forループは特別な構文です。関数や関数呼び出しとは関係ありません。


2

たぶんこれはC / C ++に特有の何かかもしれませんが、この回答を投稿します。なぜなら、あなたが説明した遅延の構文は主にC-Syntaxの影響を受けるからです。

以前に答えられた質問に加えて、技術的な観点からは、それはまた、C(およびC ++)ではコンマが実際には演算子であるため、オーバーロードすることもできます。operator;()セミコロンは公理的表現のターミネータであるため、セミコロン演算子()を使用すると、コンパイラの記述が難しくなる可能性があります。

この興味深い点は、コンマが言語全体でセパレータとして広く使用されているという事実です。コンマ演算子は例外であるようです。これは主にfor、複数の条件が機能する-loops を取得するために使用されます。

実際、operator,は、定義、引数リストなどのように同じことを行うために構築されています。式を分離するために構築されています-構文構造で,はできないことです。標準で定義されているもののみを分離できます。

ただし、セミコロンは分離しません- 終了します。そして、これも元の質問に私たちを導くものです:

for (int a = 0, float b = 0.0f; a < 100 && b < 100.0f; a++, b += 1.0f)
    printf("%d: %f", a, b);

コンマは3つのループ部分の式を区切りますが、セミコロンはループ定義の一部(初期化、条件、または後付け)を終了します。

新しいプログラミング言語(C#など)では、コンマ演算子のオーバーロードが許可されない場合がありますが、構文を変更するのは不自然に感じられるため、ほとんどの場合シンタックスは保持されます。


この議論には問題があります。でfor声明;記号がはっきりセパレータとして使用されています。ステートメントの3つの構文部分を分離します。プログレッシブ式リストを「終了」するための3番目のセミコロンはありません。別のトークンで終了します- )
スティーブンC

0

私にとっては、言語的な意味とはあまり似ていない意味が使われています。コンマはリストとセミコロンで使用され、より多くの部分があります。

ではfunc(a, b, c)、私たちは、引数のリストを持っています。

instruction1; instruction2; instruction3 多分リストですが、個別の独立した命令のリストです。

一方、for ( init1, init2; condition; inc1, inc2 )初期化のリスト、条件、増分式のリストという3つの部分があります。


0

最も簡単な表示方法は次のとおりです。

for(x = 0; x < 10; x++)

は:

for(
x = 0;
x < 10;
x++
)

言い換えれば、これらのx = 0は、実際にはパラメーターではなくステートメント/命令です。そこにステートメントを挿入します。したがって、それらはセミコロンで区切られます。

実際、それらをコンマで区切る方法はありません。x <10のようなものをパラメーターとして最後に挿入するのはいつですか?x <10を一度コンピューター化し、その操作の結果をパラメーターとして挿入する場合は、これを行います。したがって、コンマの世界では、x <0の値を関数に渡したい場合、x <10を指定します。

ここでは、ループが渡されるたびにプログラムがx <10をチェックするように指定します。だからそれは命令です。

x ++は間違いなく別の命令です。

これらはすべて指示です。したがって、それらはセミコロンで区切られます。


声明ではありません。これは、セミコロンで区切られた式です。文はまったく異なります。

x <10は式である場合があります(通常セミコロンで区切られます。x= 0は間違いなくステートメント/指示です。
user4951

CのためのBNFは -ループだった文に、1は、別として、他の文を使用できるかどうfor switchか、return 内部ループの定義(つまりfor(int i = 0; if(i > 1024) { return; } ; switch (i % 3) { case 0; case 1: i++; case 2: i++; } ) { ... })---あなたがすることはできません。声明ではありません。代わりに、次のように定義されますfor ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>

奇妙な。int i = 0は大丈夫な式ですが、主にintを宣言してiに0を割り当てるために行います(0を返しますが、副作用として。for({int i = 0; j = i}; j <0; cout << "Hello world")できますか?または、そうだと思います。
user495113

1
@JimThio:あなたはおそらくそれに気付いていないでしょうが、「ステートメント」と「表現」は言語標準において非常に正確な意味を持っています。int i = 0間違いなく式ではありません。式を記述するルールのセットは、式を構成できるものを考慮するとかなり複雑ですが、構造TYPE NAME = EXPRESSIONはこれらのルールのいずれにも一致しません。
MSalters
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.