IMO, sono inclusi in Java e C # principalmente perché erano già presenti in C ++. La vera domanda, quindi, è perché il C ++ è così. Secondo The Design and Evolution of C ++ (§16.3):
The try
keyword is completely redundant and so are the { }
brackets except where multiple statements are actually used in a try-block or a handler. For example, it would have been trivial to allow:
int f()
{
return g() catch(xxii) { // not C++
error("G() goofed: xxii");
return 22;
};
}
However, I found this so difficult to explain that the redundancy was introduced to save support personnel from confused users.
Modifica: Per quanto riguarda il motivo per cui questo sarebbe confuso, penso che si debbano solo guardare le asserzioni errate nella risposta di @ Tom Jeffery (e, soprattutto, il numero di voti positivi ricevuti) per capire che ci sarebbe stato un problema. Per il parser, questo non è molto diverso dall'abbinamento di else
s con if
s - mancando le parentesi per forzare l'altro raggruppamento, tutte catch
le clausole corrisponderebbero al più recente throw
. Per quei linguaggi ingannevoli che lo includono, le clausole finally
farebbero lo stesso. Dal punto di vista del parser, questo non è abbastanza diverso dalla situazione attuale da notare - in particolare, come stanno le grammatiche ora, non c'è davvero nulla per raggruppare le clausole catch
- le parentesi raggruppano le dichiarazioni controllate dal % clausole dicatch
, non le clausole di cattura stesse.
Dal punto di vista della scrittura di un parser, la differenza è quasi troppo piccola da notare. Se iniziamo con qualcosa del genere:
simple_statement: /* won't try to cover all of this */
;
statement: compound_statement
| simple_statement
;
statements:
| statements statement
;
compound_statement: '{' statements '}'
catch_arg: '(' argument ')'
Quindi la differenza sarebbe tra:
try_clause: 'try' statement
e
try_clause: 'try' compound_statement
Allo stesso modo, per le clausole di cattura:
catch_clause: 'catch' catch_arg statement
vs.
catch_clause: 'catch' catch_arg compound_statement
La definizione di un blocco try / catch completo non dovrebbe comunque essere modificata. Ad ogni modo sarebbe qualcosa di simile:
catch_clauses:
| catch_clauses catch_clause
;
try_block: try_clause catch_clauses [finally_clause]
;
[Qui sto usando [whatever]
per indicare qualcosa di opzionale, e sto tralasciando la sintassi per un finally_clause
dal momento che non penso che abbia alcun impatto sulla domanda.]
Anche se non provi a seguire tutte le definizioni della grammatica Yacc-like, il punto può essere riassunto abbastanza facilmente: quell'ultima istruzione (che inizia con try_block
) è quella in cui le clausole catch
vengono confrontate con clausole try
- e rimane esattamente uguale se le parentesi sono richieste o meno.
Per reiterare / riepilogare: le parentesi raggruppano insieme le istruzioni controllate da il catch
s, ma fanno non raggruppano il catch
s stessi. In quanto tali, queste parentesi hanno assolutamente un effetto no al momento di decidere quale catch
debba andare con quale try
. Per il parser / compilatore l'attività è ugualmente facile (o difficile) in entrambi i casi. Nonostante ciò, @ la risposta di Tom (e il numero di voti positivi ricevuti) fornisce un'ampia dimostrazione del fatto che un simile cambiamento vorrebbe quasi certamente confondere gli utenti.