try-catchにブラケットが必要なのはなぜですか?


38

さまざまな言語(少なくともJava、C#も考えますか)では、次のようなことができます

if( condition )
    singleStatement;

while( condition )
    singleStatement;

for( var; condition; increment )
    singleStatement;

したがって、ステートメントが1つしかない場合、を使用して新しいスコープを追加する必要はありません{ }。try-catchでこれができないのはなぜですか?

try
    singleStatement;
catch(Exception e)
    singleStatement;

常に新しいスコープなどを必要とするtry-catchについて特別なものはありますか?もしそうなら、コンパイラはそれを修正できませんでしたか?


3
NITピッキングここでは厳密にするために言えば、for部品は次のように命名されなければならないinitialconditionstepとしてinitial必要変数を定義しないと、step増分である必要はありません。
ヨアヒムザウアー

4
サイドノートとして、Dは単一のステートメントを中括弧で囲む必要はありませんcatchブロックを試してください
ラチェットフリーク

13
私は本当の質問は逆だと思う:なぜいくつかの構造は「裸の」文を許可するのか?一貫性を保つために、ブレースはどこでも必須です。
アンクルゼイフ

3
@UncleZeiv-後に続くものifが常に単一のステートメントであり、中括弧で囲まれた複数のステートメントが単一のステートメントを構成すると考える場合、矛盾はありません。しかし、私は...いつもとにかく、そうでカッコを置か者の一人だ
detly

1
私も括弧を書く傾向にあるが、私はのような直接的な出口点を持っているときにそれらを書くことではないが好きthrowreturn、そして@detlyのように言った、あなたはステートメントの単一のグループとしてかっこを考えるならば、私はそれを見つけることができません。一貫性がありません。私は、人々によって言及されたこれらの「多くのコーディングエラー」が何であるかを理解したことがありません。... Pは、これで問題があったことがない:人々は、適切なインデントを使用してユニットテストを持って、彼らが何をするかに注意を払って起動する必要があります
Svish

回答:


23

IMO、これらは主にC ++にすでに存在するため、JavaおよびC#に含まれています。本当の問題は、C ++がなぜそうなのかということです。よるCの設計と進化++(§16.3):

このtryキーワードは完全に冗長であるため{ }、複数のステートメントがtryブロックまたはハンドラーで実際に使用される場合を除き、括弧も完全に冗長です。たとえば、以下を許可するのは簡単なことです。

int f()
{
    return g() catch(xxii) { // not C++
        error("G() goofed: xxii");
        return 22;
    };
}

しかし、サポート担当者を混乱したユーザーから守るために冗長性が導入されたことを説明するのは非常に難しいと感じました。

編集:なぜこれが混乱するかについては、問題があることを認識するために、@ Tom Jefferyの答え(および特に、それが受け取ったアップ投票の数)の誤った主張を見るだけでよいと思います。パーサーにとって、これはelsesとifsのマッチングと実際には違いはありません。他のグループ化を強制する中括弧がなく、すべての catch句が最新のに一致しthrowます。それを含む誤って誤解された言語については、finally条項も同じことをします。パーサーの観点から見ると、これは現在の状況と気づくのに十分な違いはありません-特に、現在の文法では、catch句をグループ化することは本当にありません-括弧は、catch catch句ではなく句。

パーサーを書くという観点から見ると、その差はほとんど気付かないほどです。このようなものから始める場合:

simple_statement: /* won't try to cover all of this */
                ;

statement: compound_statement
         | simple_statement
         ;

statements: 
          | statements statement
          ;

compound_statement: '{' statements '}'

catch_arg: '(' argument ')'

次に、違いは次のようになります。

try_clause: 'try' statement

そして:

try_clause: 'try' compound_statement

同様に、catch句の場合:

catch_clause: 'catch' catch_arg statement

catch_clause: 'catch' catch_arg compound_statement

ただし、完全なtry / catchブロックの定義を変更する必要はまったくありません。いずれにしても、それは次のようなものになります。

catch_clauses: 
             | catch_clauses catch_clause
             ;

try_block: try_clause catch_clauses [finally_clause]
         ;

[ここでは[whatever]、オプションの何かを示すために使用していますが、aの構文は省略しています。finally_clauseなぜなら、それが問題に関係しているとは思わないからです。]

そこにあるYaccのような文法の定義すべてに従おうとしない場合でも、ポイントはかなり簡単に要約できます:最後のステートメント(で始まるtry_block)は、catch句が句と一致するものでtryあり、正確にそのままです中かっこが必要かどうかに関係なく同じです。

繰り返し/要約する:中括弧は、s によって制御されるステートメントをグループ化しますcatchが、s自体グループ化しませcatch。そのため、これらの中括弧は、どちらがどちらを使用するかを決定する際にまったく効果がありません。パーサー/コンパイラの場合、タスクはどちらの方法でも同様に簡単(または難しい)です。それにも関わらず、@ Tomの回答(および受け取った賛成票の数)は、そのような変更ユーザーを混乱させることほぼ確実であるという事実の十分な実証を提供します。catchtry


OPはtryとcatchブロックの両方を囲む括弧について尋ねていますが、これはtryの周りのものを参照しているようです(最初の段落は両方を参照すると理解できますが、コードは前者のみを示しています)...明らかにする?
Shog9

@ Mr.CRT:「キャッチブロック」は、それ以外の場合は「ハンドラ」として知られます。これについては上記の引用を参照してください。
ジェリーコフィン

3
BAH、単に削除するには、私のコメントを編集しているあいまいさを。私が得ているのは、ブラケットなしの構造どのように機能するかを説明するために長くした場合、トムの(上記の)よりも効果的な答えかもしれないが、混乱した方法である(トムの答えに関するビリーのコメントは動作しなかっ可能性があることを暗示してますが、これは間違っていると思います)。
Shog9

@JerryCoffinあなたの答えを広げてくれてありがとう:今は私にとってずっと明確だ。

try return g(); catch(xxii) error("G() goofed: xxii");whouldはまだきちんとしているIMO
alfC 14

19

ブラケットがいくつかの単一の文の構造ではなく、他人のために必要とされる理由について答え、エリックリペットは書きました:

「裸の」ステートメントを許可するのではなく、C#でステートメントのブレースブロックを必要とする場所がいくつかあります。彼らです:

  • メソッド、コンストラクタ、デストラクタ、プロパティアクセサ、イベントアクセサ、またはインデクサアクセサの本体。
  • try、catch、finally、checked、unchecked、またはunsafe領域のブロック。
  • ステートメントラムダまたは匿名メソッドのブロック
  • ブロックにローカル変数宣言が直接含まれている場合のifまたはloopステートメントのブロック。(つまり、「while(x!= 10)int y = 123;」は不正です。宣言を中括弧で囲む必要があります。)

これらの各ケースでは、単一の括弧なしステートメントが合法である機能に対して、明確な文法(または曖昧な文法を明確にするための発見的手法)を考え出すことができます。しかし、ポイントは何でしょうか?これらの状況のそれぞれで、複数のステートメントが表示されることを期待しています。単一のステートメントはまれであり、まれなケースです。これらの非常にありそうもないケースのために文法を曖昧にすることは本当に価値がないように思われます。

言い換えれば、コンパイラーチームが実装するのは、それが提供するわずかな利点のために正当化されるよりも高価でした。


13

他のスタイルの問題を回避するためだと思います。次はあいまいです...

try
    // Do stuff
try
    // Do  more stuff
catch(MyException1 e1)
    // Handle fist exception
catch(MyException2 e2)
    // So which try does this catch belong to?
finally
    // and who does this finally block belong to?

これは次のことを意味します。

try {
   try {

   } catch(Exception e1) {

   } catch(Exception e2) {

   } 
} finally {

} 

または...

try {
   try {

   } catch(Exception e1) {

   } 
} catch(Exception e2) {

} finally {

} 

24
このあいまいさは、ifforに適用されます。問題は、なぜifおよびswitchステートメントでは許可されているがtry / catchでは許可されていないのですか?
ディパンメータ

3
@Dipanフェアポイント。括弧のないifを許可することで、Cなどの古い言語と一貫性を保とうとするJava / C#の問題なのでしょうか。try / catchはより新しい構成であるので、言語設計者は伝統に違反しても構わないと考えました。
トムジェフリーズ

少なくともCとC ++については、強制に答えてみました。
ディパンメタ

6
@DipanMehta:ifケースに複数の可能性のある宙ぶらりんのelse節がないため。「elseは最も内側のifにバインドされている」と言って、それで完了します。しかし、try / catchでは機能しません。
ビリーONeal

2
@ビリー:if / if ifに存在する潜在的なあいまいさをあなたは理解していると思います。角括弧を使用しない特定の構造。ジェリーの答え、これ混乱を避けるために行われた意識的な選択であったことを暗示しています、確かにうまくいくはずです-if / if elseで「機能する」ように。
Shog9

1

主な理由は、1行だけのtry / catchブロックを必要とするC#でできることはほとんどないためだと思います。(頭のてっぺんのことは今は考えられません)。catchブロックに関しては有効なポイントがあります。たとえば、何かを記録する1行のステートメントですが、読みやすさの観点からは(少なくとも私にとって){}を要求する方が理にかなっています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.