En mi opinión, están incluidos en Java y C # principalmente porque ya existían en C ++. La verdadera pregunta, entonces, es por qué C ++ es así. De acuerdo con el diseño y la evolución de C ++ (§16.3):
La try
palabra clave es completamente redundante y también lo son los { }
corchetes, excepto cuando se usan varias declaraciones en un bloque de prueba o un controlador. Por ejemplo, hubiera sido trivial permitir:
int f()
{
return g() catch(xxii) { // not C++
error("G() goofed: xxii");
return 22;
};
}
Sin embargo, encontré esto tan difícil de explicar que se introdujo la redundancia para salvar al personal de soporte de usuarios confusos.
Editar: En cuanto a por qué esto sería confuso, creo que uno solo tiene que mirar las afirmaciones incorrectas en la respuesta de @Tom Jeffery (y, especialmente, el número de votos positivos que ha recibido) para darse cuenta de que habría un problema. Para el analizador, esto realmente no es diferente de hacer coincidir else
s con if
llaves que carecen de s para forzar otra agrupación, todas las catch
cláusulas coincidirían con las más recientes throw
. Para aquellos lenguajes erróneos que lo incluyen, las finally
cláusulas harían lo mismo. Desde el punto de vista del analizador, esto no es lo suficientemente diferente de la situación actual como para darse cuenta, en particular, como están las gramáticas ahora, realmente no hay nada para agrupar las catch
cláusulas; los corchetes agrupan las declaraciones controladas por elcatch
cláusulas, no las cláusulas de captura en sí.
Desde el punto de vista de escribir un analizador sintáctico, la diferencia es casi demasiado pequeña para notarla. Si comenzamos con algo como esto:
simple_statement: /* won't try to cover all of this */
;
statement: compound_statement
| simple_statement
;
statements:
| statements statement
;
compound_statement: '{' statements '}'
catch_arg: '(' argument ')'
Entonces la diferencia sería entre:
try_clause: 'try' statement
y:
try_clause: 'try' compound_statement
Del mismo modo, para las cláusulas catch:
catch_clause: 'catch' catch_arg statement
vs.
catch_clause: 'catch' catch_arg compound_statement
Sin embargo, la definición de un bloque try / catch completo no necesitaría cambiar en absoluto. De cualquier manera, sería algo como:
catch_clauses:
| catch_clauses catch_clause
;
try_block: try_clause catch_clauses [finally_clause]
;
[Aquí estoy usando [whatever]
para indicar algo opcional, y estoy dejando de lado la sintaxis para un, finally_clause
ya que no creo que tenga ninguna relación con la pregunta.]
Incluso si no intenta seguir toda la definición de gramática similar a Yacc allí, el punto puede resumirse con bastante facilidad: esa última declaración (comenzando con try_block
) es aquella en la que las catch
cláusulas se combinan con las try
cláusulas, y sigue siendo exactamente el igual si se requieren o no las llaves.
Para reiterar / resumir: las llaves agrupan las declaraciones controladas por la catch
s, pero no agrupan las catch
s mismas. Como tal, esos aparatos no tienen absolutamente ningún efecto al decidir cuál catch
va con qué try
. Para el analizador / compilador, la tarea es igualmente fácil (o difícil) de cualquier manera. A pesar de esto, la respuesta de Tom @ (y el número de up-votos que ha recibido) proporciona amplia demostración del hecho de que un tal cambio haría con los usuarios es casi seguro que confundirlo.
for
las partes debe llamarse algo asíinitial
,condition
ystep
comoinitial
no necesita definir una variable ystep
no necesita ser un incremento.