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
이 모호함에 적용 하는 경우 와 에 대한 동등하게. 질문은 : 왜 if 및 switch 문에 허용 되지만 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.