try-catch에 대괄호가 필요한 이유는 무엇입니까?


38

다양한 언어로 (Java는 적어도 C #이라고 생각합니까?)

if( condition )
    singleStatement;

while( condition )
    singleStatement;

for( var; condition; increment )
    singleStatement;

따라서 문이 하나만 있으면으로 새 범위를 추가 할 필요가 없습니다 { }. try-catch로이 작업을 수행 할 수없는 이유는 무엇입니까?

try
    singleStatement;
catch(Exception e)
    singleStatement;

항상 새로운 범위 또는 무언가를 요구하는 try-catch에 특별한 것이 있습니까? 그렇다면 컴파일러가 수정할 수 없었습니까?


3
NIT-따기 여기 : 엄밀히에 대해 말하는 for부분이 뭔가를 지정해야합니다 initial, condition그리고 step같은 initial필요 변수를 정의하지 및 step증분 할 필요는 없다.
Joachim Sauer

4
사이드 노트 D는 단일 문장 주위에 괄호가 필요하지 않습니다. catch block을 시도하십시오
ratchet freak

13
나는 실제 질문이 다른 방향으로 생각한다고 생각한다. 왜 어떤 구조는 "나체화 된"진술을 허용 하는가? 일관성을 유지하려면 모든 곳에서 중괄호를 사용해야합니다.
UncleZeiv

3
@UncleZeiv-뒤에 오는 if것이 항상 단일 명령문이고 중괄호로 묶인 여러 명령문이 단일 명령문을 구성 한다고 생각하면 일관성이 없습니다 . 하지만 난 항상 중괄호를 넣어 사람 중 하나입니다, 그래서 ...
detly

1
나는뿐만 아니라 괄호를 작성하는 경향이 있지만 나는 같은 직접 종료 지점이있을 때를 작성하지 않아도 좋아 throw하고 return당신이 문을 하나의 그룹으로 중괄호를 고려한다면, 그리고 @detly 말했듯이, 나는 그것을 발견하지 않습니다를 일관성이 없습니다. 사람들이 언급 한 "많은 코딩 오류"가 무엇인지 이해하지 못했습니다. 사람들은 단위 테스트를, 그들이 무엇에 관심을 시작하는 데 필요한 적절한 들여 쓰기를 사용하고 있습니다 : P는이 문제 ... 없었
Svish

답변:


23

IMO는 주로 C ++에 이미 존재했기 때문에 Java 및 C #에 포함되어 있습니다. 그렇다면 실제 질문은 왜 C ++이 그런 식입니까? C ++의 디자인과 진화 (§16.3) 에 따르면 :

try키워드는 완전히 중복 그래서있는 { }여러 문이 실제로 시도 블록 또는 처리기에 사용되는 경우를 제외하고 브래킷. 예를 들어, 다음을 허용하는 것이 쉽지 않을 것입니다.

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

그러나 혼란스러운 사용자로부터 지원 인력을 구하기 위해 중복성이 도입되었다는 것을 설명하기가 어렵습니다.

편집 : 이것이 왜 혼란 스럽습니까, 나는 문제가 있음을 깨닫기 위해 @Tom Jeffery의 대답 (특히 수신 된 투표 수)에서 잘못된 주장을보아야한다고 생각합니다. 파서에서 이것은 elses를 s와 일치시키는 것과 다르지 않습니다. if다른 그룹을 강제로 묶는 중괄호가 없으면 모든 catch 절이 가장 최근의 것과 일치합니다 throw. 잘못 포함 된 languags에 대해서도 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

vs.

catch_clause: 'catch' catch_arg compound_statement

완전한 try / catch 블록의 정의는 전혀 변경할 필요가 없습니다. 어느 쪽이든 그것은 다음과 같습니다.

catch_clauses: 
             | catch_clauses catch_clause
             ;

try_block: try_clause catch_clauses [finally_clause]
         ;

[여기서는 [whatever]선택 사항을 나타내는 데 사용 하고 finally_clause있으며 질문과 관련이 있다고 생각하지 않기 때문에 구문을 생략합니다 .]

당신은 따라하지 않는 경우에도 모든 Yacc에-처럼이 문법 정의 점은 매우 쉽게 요약 될 수있다 : 마지막 문 (로 시작하는 것이이 try_block) 하나입니다 catch절이와 일치 얻을 try조항 - 그것은 남아 정확히 중괄호가 필요한지 여부에 관계없이 동일합니다.

/ 요약한다 반복하려면 다음과 같이 괄호 그룹 제어 명령문 에 의해catch 의,하지만 할 수 없는 그룹이 catch자신이야. 따라서, 그 괄호는 전혀 없습니다 있는 결정에 따라 효과가 catch있는 이동을 try. 파서 / 컴파일러의 경우 작업은 어느 쪽이든 똑같이 쉽다 (또는 어렵다). 그럼에도 불구하고 @Tom의 답변 (및 수신 된 투표 수)은 그러한 변경 사용자를 혼란스럽게 할 것이라는 사실을 충분히 보여줍니다 .


영업 이익은 시도하고 모두 주위의 괄호에 대해 요구하고있다 catch 블록 이 나타납니다가 주변 사람들 참조 할 때, 시도 ... 당신을 수 (첫 번째 단락은 모두를 참조하는 것으로 이해 될 수 있지만 코드는 이전의 설명) 밝히다?
Shog9

@ Mr.CRT : "캐치 블록"은 "핸들러"로 알려져 있으며, 위의 인용문을 참조하십시오.
Jerry Coffin

3
bah, 방금 내 의견을 편집하여 모호성 을 제거 했습니다 . 내가 얻는 것은 괄호가없는 구조 어떻게 작동했는지 설명하기 위해 더 오래 갈 경우 Tom (위)보다 더 효과적인 대답이 될 수 있다는 것입니다. 그것이 효과가 없었다는 것을 암시하는 것은 잘못된 것입니다).
Shog9

@JerryCoffin 귀하의 답변을 확장 해 주셔서 감사합니다. 지금 훨씬 더 명확합니다.

try return g(); catch(xxii) error("G() goofed: xxii");whould 여전히 깔끔한 IMO
alfC

19

괄호가 어떤 단일 문장 구조가 아니라 다른 사람을 위해 요구되는 이유에 대한 대답 , 에릭 Lippert의 작성 :

C #에서 "네이 키드 (naked)"문을 허용하는 대신 괄호로 묶는 문 블록이 필요한 곳이 많이 있습니다. 그들은:

  • 메소드의 본문, 생성자, 소멸자, 속성 접근 자, 이벤트 접근 자 또는 인덱서 접근 자
  • 시도, 캐치, 마지막으로 검사, 검사 또는 안전하지 않은 영역의 블록.
  • 명령문 람다 또는 익명 메소드의 블록
  • 블록에 로컬 변수 선언이 직접 포함되어있는 경우 if 또는 loop 문의 블록 (즉, "(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
이 모호함에 적용 하는 경우에 대한 동등하게. 질문은 : 왜 ifswitch 문에 허용 되지만 try / catch 에는 허용 되지 않는 것 입니까?
Dipan Mehta

3
@ 디판 페어 포인트. 괄호가없는 if를 허용하여 C와 같은 오래된 언어와 일관성을 유지하려는 Java / C #의 문제인지 궁금합니다. try / catch는 새로운 구조 인 반면, 언어 디자이너는 전통을 깨뜨리는 것이 좋다고 생각했습니다.
Tom Jefferys

나는 적어도 C와 C ++에 대해 강박에 답하려고 노력했다.
Dipan Mehta

6
@DipanMehta : if사례에 대해 가능한 dangling else 절이 여러 개 없기 때문 입니다. "다른 사람이 가장 안쪽에 바인딩되어있다"고 말하기 만하면됩니다. 그러나 시도 / 캐치의 경우 작동하지 않습니다.
Billy ONeal

2
@ 빌리 : 만약 당신이 if / if에 존재하는 잠재적 인 모호성을 무시하고 있다고 생각합니다 ... "말하기 쉽다"라고 말하기는 쉽지만, 그것은 우연히도 허용하지 않는 모호성을 해결하기위한 어려운 규칙이 있기 때문입니다. 대괄호를 사용하지 않는 특정 구조. Jerry의 대답 이것이 혼란을 피하기 위해 만들어진 의식적인 선택 이었다는 것을 암시 하지만, 그것이 다른 경우 if / if에서 "작동"하는 것처럼 분명히 효과 있었을 것입니다.
Shog9

1

주된 이유는 C #에서 한 줄에 불과한 try / catch 블록이 필요한 작업이 거의 없기 때문이라고 생각합니다. (나는 지금 내 머리 꼭대기를 전혀 생각할 수 없다). catch 블록과 관련하여 유효한 점이있을 수 있습니다. 예를 들어, 무언가를 기록하는 한 줄 명령문이지만 가독성 측면에서는 {}을 요구하는 것이 더 합리적입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.