for-eachに「in」の代わりにコロンがあるのはなぜですか?


9

Java 5言語ガイドから

コロン(:)が表示されたら、「中」と読みます。

inでは、そもそも使ってみませんか?

これは何年もの間私を悩ませてきました。他の言語と矛盾しているからです。たとえば、Java では、C ++、Scala、Rubyのようなシンボルの代わりに、型間の関係implementsextends、がありますsuper

5つのコンテキストで使用されるJavaコロン。3つはCから継承され、他の2つはJoshua Blochによって承認されました。少なくとも、それは彼が「閉鎖論争」の話の間に言ったものでした。これは、for-eachのセマンティクスと矛盾するマッピングとしてのコロンの使用を批判したときに発生します。これは、for-eachが乱用された予想パターンであるため、私には奇妙に思えます。同様list_name/category: elementslaberl/term: meaning

私はjcpとjsrを調べましたが、メーリングリストの兆候は見つかりませんでした。この問題に関する議論はグーグルによって見つかりませんでした。のコロンの意味に戸惑う初心者のみfor


inこれまでに提供されたものに対する主な議論:

  • 新しいキーワードが必要です。そして
  • 字句解析を複雑にします。

関連する文法定義を見てみましょう:

ステートメント
    : 'for' '(' forControl ')'ステートメント
    | ...
    ;

forControl
    :EnhancedForControl
    | forInit?「;」表現?「;」forUpdate?
    ;

EnhancedForControl
    :variableModifier *タイプvariableDeclaratorId ':'式
    ;

から変更する:in、複雑さが増したり、新しいキーワードが必要になったりしません。


1
言語デザイナーの動機を見つけるための最良の情報源は、多くの場合デザイナー自身です。とは言っても、これは明らかにイテラブルよりも単なる構文上の砂糖です。stackoverflow.com/questions/11216994/…を
Robert Harvey

回答:


8

通常教えられる通常のパーサーは、パーサーが入力に触れる前に、字句解析器ステージを持っています。レクサー(「スキャナー」または「トークン化ツール」も)は、タイプで注釈が付けられた小さなトークンに入力を切り分けます。これにより、メインパーサーは各文字を端末として扱う必要がなく、トークンを端末要素として使用できます。これにより、効率が著しく向上します。特に、レクサーはすべてのコメントと空白を削除することもできます。ただし、個別のトークナイザーフェーズは、キーワードが識別子としても使用できないことを意味します(言語が好意から外れたストロッピングをサポートしないか、すべての識別子の前にのようなシギルを付ける場合を除く$foo)。

どうして?次のトークンを理解する単純なトークナイザーがあるとしましょう:

FOR = 'for'
LPAREN = '('
RPAREN = ')'
IN = 'in'
IDENT = /\w+/
COLON = ':'
SEMICOLON = ';'

トークナイザーは常に最長のトークンと一致し、識別子よりもキーワードを優先します。だから、interestingとしてレクサー処理されますIDENT:interestingが、inとしてレクサー処理されませんINように、決してIDENT:interesting。次のようなコードスニペット

for(var in expression)

トークンストリームに変換されます

FOR LPAREN IDENT:var IN IDENT:expression RPAREN

これまでのところ、うまくいきます。しかし、どの変数も、コードではなく変数ではなくinキーワードとして字句解析されINます。レクサーはトークン間の状態を保持せずin、forループにいる場合を除いて、通常は変数である必要があることを認識できません。また、次のコードは合法である必要があります。

for(in in expression)

1 inつ目は識別子、2つ目はキーワードです。

この問題には2つの反応があります。

コンテキストキーワードはわかりにくいので、代わりにキーワードを再利用しましょう。

Javaには多くの予約語がありますが、C ++からJavaに切り替えるプログラマに役立つエラーメッセージを提供する以外に、その一部は使用できません。新しいキーワードを追加すると、コードが壊れます。コンテキストキーワードを追加すると、構文の強調表示が適切でない限り、コードの読者は混乱し、より高度な解析手法を使用する必要があるため、ツールの実装が難しくなります(以下を参照)。

言語を拡張したい場合、唯一の健全なアプローチは、以前はその言語では合法でなかった記号を使用することです。特に、これらを識別子にすることはできません。foreachループ構文により、Javaは既存の:キーワードを新しい意味で再利用しました。ラムダでは、Javaが追加->(以前に法的なプログラムで発生することができなかったキーワードを-->まだとしてレクサー処理されるだろう'--' '>'合法であり、これは->以前としてレクサー処理されている場合があります'-', '>'が、そのシーケンスは、パーサーによって拒否されるだろう)。

コンテキストキーワードは言語を簡素化し、実装しましょう

レクサーは間違いなく便利です。ただし、パーサーの前にレクサーを実行する代わりに、パーサーと連携して実行できます。ボトムアップパーサーは常に、任意の場所で受け入れられるトークンタイプのセットを認識しています。次に、パーサーは、現在の位置でこれらのタイプのいずれかに一致するようにレクサーに要求できます。for-eachループでは·、変数が見つかった後、パーサーは(簡略化された)文法で示される位置にあります。

for_loop = for_loop_cstyle | for_each_loop
for_loop_cstyle = 'for' '(' declaration · ';' expression ';' expression ')'
for_each_loop = 'for' '(' declaration · 'in' expression ')'

その位置では、正当なトークンはSEMICOLONor INですが、ではありませんIDENT。キーワードinは完全に明確です。

この特定の例では、上記の文法を次のように書き換えることができるため、トップダウンパーサーにも問題はありません。

for_loop = 'for' '(' declaration · for_loop_rest ')'
for_loop_rest =  · ';' expression ';' expression
for_loop_rest = · 'in' expression

そして、決定に必要なすべてのトークンは、バックトラックすることなく見ることができます。

使いやすさを考慮する

Javaは常に、意味的および構文的な単純化に向かっています。たとえば、言語はコードをはるかに複雑にするため、演算子のオーバーロードをサポートしていません。そのため、for-eachループ構文間inを決定するとき:は、混乱が少なく、ユーザーにとってわかりやすい構文を検討する必要があります。極端なケースはおそらく

for (in in in in())
for (in in : in())

(注:Javaには、型名、変数、およびメソッド用の個別の名前空間があります。これは間違いであると思います。これは、ほとんどの場合、これは、後の言語設計でさらに間違いを追加する必要があることを意味しません。)

反復変数と反復コレクションの間の視覚的な分離を明確にするのはどの選択肢ですか?コードを見たときに、どの代替案がより迅速に認識されますか?これらの基準に関しては、記号を分離することは一連の単語よりも優れていることがわかりました。他の言語は異なる値を持っています。たとえば、Pythonは多くの演算子を英語で表記しているため、自然に読みやすく、理解しやすくなっていますが、同じ特性のため、Pythonを一目で理解するのは非常に困難です。


17

以下のため、各ループ構文は、あなたが作る必要があるだろうのJava 5で追加されましたin、それは既存のコードを壊すので、言語のキーワードを、後の言語にキーワードを追加すると、あなたはすべてのコストで避けるものだ-という名前の突然すべての変数in の解析、原因をエラー。enumその点で十分に悪かった。


2
それは...不便なようです。これは、言語デザイナーが必要なキーワードのほとんどを最初から予測するのに十分であると想定しています。それが必要かどうかさえわかりません。まともなコンパイラは、キーワードがそのコンテキストによって変数であるかどうかを判断できます。
Robert Harvey

2
Javaには、C#のようなコンテキストキーワードはないと思います。したがって、使用inすると、新しいキーワードが導入され、下位互換性が失われます(System.in、誰か?)、または以前は知られていないまったく新しいコンセプト(コンテキストキーワード)が導入されます。何のために?
イェルクWミッターク

2
コンテンツキーワードにはどのような害がありますか?
user2418306

5
@ user2418306言語が個別のレクサーフェーズで解析されない限り、キーワードを追加しても既存のコードを壊す必要はありません。特に、「in」for(variable in expression)を変数に使用できる場合でも、「in」in が正当なコードとあいまいになることはありません。ただし、多くのコンパイラツールチェーンでは、別個のレクサーフェーズが非常に一般的です。これは、いくつかの一般的なパーサージェネレーターでJavaを解析することを不可能または少なくともはるかに難しくします。言語の構文を単純に保つことは、通常、関係者全員にとって良いことです。誰もがC ++やPerlのような構文上の怪物を必要としているわけではありません。
amon 2016年

1
@RobertHarvey:DOはそれを忘れていないconstし、gotoJavaで両方の予約語ですが、(まだ)使用されていません。
TMN
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.