C++ Exception

Tags:

리누스는 C++를 싫어해…

the whole C++ exception handling thing is fundamentally broken. It’s _especially_ broken for kernels.

아마도 다음과 같은 이유때문에 예외처리의 문제점을 지적한듯: EXCEPTION HANDLING: A FALSE SENSE OF SECURITY. 최근에 Scott Myers가 진행하는 C++에 대한 이야기들에 소개되서 읽어본 문서입니다.

template
void Stack::push(T element)
{
top++;
if( top == nelems-1 ){
T* new_buffer = new T[nelems+=10];
if( new_buffer == 0 )
throw “out of memory”; // (1)
for(int i = 0; i < top; i++) new_buffer[i] = v[i]; delete [] v; v = new_buffer; } v[top] = element; } [/code] 와 같은 stack 의 push가 있다고 할때 (1)에서 예외가 발생한다면, top++이 이미 수행되었으므로 문제. [code lang="cpp"] template void Stack::push(T element) { top++; if( top == nelems-1 ){ T* new_buffer = new T[nelems+=10]; if( new_buffer == 0 ) throw "out of memory"; // (1) for(int i = 0; i < top; i++) new_buffer[i] = v[i]; // (2) delete [] v; v = new_buffer; } v[top] = element; } [/code] 이렇게 해결한다면 보시다시피 (1)의 시점에서 throw되면 T* new_buffer에 new한 내용은 leak. 여기가 잘되었다고 하더라도, (2)에서 만약 T의 operator= 가 throw하게된다면 역시나 T* new_buffer에 할당한 내용은 leak. 결국 C++의 예외처리가 어렵다..라는 것은 이를 의미하는 것일 듯 합니다. Exceptional C++에 예외처리에 대해 잘 다루고 있지만, 번역서를 샀는데 번역이 개판이라 망연자실중.

Comments

33 responses to “C++ Exception”

  1. 이원구 Avatar

    결국 exception이라는 것도 하나의 도구인 것 같습니다. 어떻게 사용하느냐에 따라 도움이 될 수도 있지만 코드를 망치기도 하죠.
    그래도 몇가지 규칙만 잘 지킨다면 그리 어렵지 않게 exception-safe한 코드를 작성할 수 있습니다. 사실 잘 만들어진 exception-safe한 프로그램에는 try-catch가 그리 많지 않죠. RAII 클래스들이 대신 rollback 작업을 해주니까요.

  2. 세라비 Avatar

    C++에서는 stroustrup부터 RAII idiom을 권장하고 있습니다. exception 발생 시 stack rewind 하면서 가장 자연스럽게 resource allocation 등의 side-effect를 제거할 수 있기 때문이죠. Java의 exception 라고 해서 이러한 문제가 깔끔하게 해결된 것은 아닙니다. 다만 resource가 메모리인 경우에만 GC가 자동적으로 해결해줄 뿐이죠.

    제 생각에 위에서 예를 든 exception 처리의 복잡도는 에러 처리 자체의 복잡도에서 발생하는 것이지 exception이라는 facility에서 발생하는 것은 아니라고 생각합니다. 에러 처리를 C의 if문으로 해결한다고 하더라도 상응하는 side-effect는 직접 해결해주어야할 뿐이죠. RAII idiom을 잘 활용하면 거의 신경안쓰고 깔끔한 코드를 만들어낼 수 있죠.

    이원구님 말씀대로 exception도 도구에 불과하고, 저도 어떤 팀이 exception을 잘 활용할 수 있을 정도로 C++ 개발에 숙련되지 않았다면 exception을 쓰지말라고 권장합니다.

  3. MKSeo Avatar
    MKSeo

    자바의 경우에는 적어도 C++ 보다는 단순합니다. checked exception인 경우 반드시 throws를 적어야하고, throws가 다르면 인터페이스도 다르다고 인식해버리므로 위와같이 T operator= 에 의한 예상키 힘든 상황을 만나리란 가능성은 무척 낮아집니다. (그렇다고 checked exception이 더 좋다는 말은 아닙니다. 그냥 상황이 그렇다는 말씀..) 물론 메모리 이외에 다른 invariants들을 잘 지켜주기 위해서는 많은 노력이 필요한 것에는 동의합니다.

    Linus의 경우엔 exception으로 인해 오히려 예외처리가 복잡해지니까 이를 fundamentally broken 이라고 쓴게 아닌가 생각됩니다. 그리고 그것을 해결하려면 RAII를 해야하는데, 그게 오버헤드라고 봤을거라고 역시 생각됩니다.

  4. 이원구 Avatar

    예전 자바로 프로그램을 처음 만들면서 제일 당황스러웠던 것중의 하나가 RAII가 안된다는 것이었던 기억이… try-catch-finally로 해야 했던가요? 암튼 불편했던 기억이 납니다. 물론 eclipse가 알아서 catch 코드를 붙여 주었지만요. :-)
    자바도 명시적으로 이 메모리는 GC를 사용하겠다, 아니면 scope가 끝나면 지워져라라고 지정할 수 있으면 좋을텐데요.

    그리고 리눅스 커널의 코드는 굳이 C++를 사용하지 않아도 관리가 가능한 정도라고 생각됩니다. 물론 제가 본 커널 코드라 봤자 커널 책을 읽으면서 같이 본 정도지만요. 역시 한줄 한줄 빈틈이 없는 코드더군요. @_@

    하지만 오피스같은 덩치의 프로그램을 C로 짜라면 문제가 있지 않을까 싶습니다. 역시 도메인에 맞는 언어라는게 있는거겠죠? :-)

    리누스에게는 조금 편리한 기계어 정도가 필요하지 않았나 싶습니다. :-)

  5. MKSeo Avatar
    MKSeo

    음 그렇죠. 자바엔 C++ 처럼 스코프를 벗어나면서 딱 자원을 정리해주는게 없죠. 그게 깝깝한 점이고요.. 제가 알기로는 윈도우가 2000인가 2003부터 C++로 코드를 옮겨갔는데 뭐 굳이 리눅스라고 안될것도 없지 않나 싶은데, 리누스가 싫다면 어쩔 수 없는거죠;; 근데 그게 아니더라도 커널 코딩하는 사람들은 뭐랄까 apps 개발하는 사람들은 그냥 넘겨도 되는 작은 오버헤드에도 민감한 듯..

  6. CN Avatar

    C#이라면 using block으로 비슷한 형태를 흉내낼 수는 있을텐데 Java에는 없는 것인가요?

  7. MKSeo Avatar
    MKSeo

    자바엔 없습니다.
    일단 예외에 안전하게 자원을 해제하는건 코딩을 잘 해야하구요.
    메모리는 C#이나 자바나 마음대로 해제가 안되잖아요.

  8. 공성식 Avatar
    공성식

    C#의 using 구문은 단순히 syntax sugar에 불과합니다.
    그러므로 Java에서도 동일하게 구현할 수 있다고 생각합니다.

    using (C obj = new C()) {
    obj.F();
    }

    위의 코드는 다음의 코드와 사실상 동일합니다.
    (실행해 본 코드는 아니라 약간 부정확할 수 있습니다.)

    C obj = new C();
    try {
    obj.F();
    finally {
    if (obj != null) obj.Dispose();
    }

    단, 위에서 C 클래스는 IDisposable을 구현해야 합니다.
    using 구문이 없어도 try…finally 를 이용하면 동일한 효과를 볼 수 있습니다.

  9. mkseo Avatar
    mkseo

    네 동일하게 구현할 수 있습니다.
    문젠 제대로 짜는 사람들이 많지 않다는 거.
    대표적인 예가 jdbc의 connection인데요.

    Connection con = null;
    PreparedStatement pstmt = null;
    try {
    con = xxxx.getConnection();
    pstmt = con.prepareStatement(…);
    // sql 실행
    }

    finally {
    if (pstmt != null) try { pstmt.close(); } catch(Exception e) { }
    if (con != null) try { con.close(); } catch(Exception e) { }
    }

    이런 DAO 몇개 짜고 나면 나중에는 null 초기화후 try – finally 하고
    close하면서 매번 다시 try-catch로 묶는게 얼마나 힘든지 모릅니다.
    타이핑 노동이죠;

  10. 공성식 Avatar
    공성식

    사실 보여주신 예는 어떤 언어로 구현해도 간단하지는 않을 것 같습니다.
    외부 자원과 인터페이스하다 보면 예외 상황이 워낙 많으니까요.
    C#의 using구문을 써도 마찬가지로 복잡할 테구요.
    그래도 다행인 것은 이런 복잡한 것을 encapsulate하여 재사용하면 반복적인 코딩은 꽤 줄일 수 있다는 것입니다.

    void doQuery(connectionString, sql)
    throws IOException, SQLException {
    //establish a connection and query in try…finally
    }

    이런 식으로 하나만 좀 공들여 만들어 놓고 재사용을 하면 타이핑은 많이 줄일 수 있지 않을까요?

    물론 이렇게 할 경우
    try { pstmt.close(); } catch(Exception e) { } 처럼 exception swallowing 은 별로 좋지 않을 것 같습니다.
    메소드 밖으로 Exception을 알려줘야 할 테니까요. (Fail loudly!)

    본문의 주제로 돌아가서…
    제 생각에 structured error handling 자체는 훌륭한 개념이라고 생각합니다.
    다만 민구님 말씀처럼 정말 제대로 만드는 것이 C에서의 에러 핸들링보다 어렵다고나 할까요.
    그렇지만 제 경험으로는 structured error handling 방식이 에러 코드 리턴이나 글로벌 에러 코드나 VB에서의 on error goto … 보다는 훨씬 편리하고 우아하게 코딩할 수 있더라구요.

  11. MKSeo Avatar
    MKSeo

    네.. 공성식님이 말씀하신대로 접근 클래스를 하나 만들면 좋죠.

    그런데 try { pstmt.close(); } catch(Exception e) { } 는 로그정도는 남길 수 있을지 모르겠지만, 실패할 일도 거의 없어보이고 사실 실패해도 아무것도 할 수 있는게 없습니다. 컨넥션을 닫다가 죽었다… 그럼 할수 있는게 거의 없죠. close하다가 죽는건 컨넥션을 open하다가 죽는거랑은 또 다릅니다.

    저는 통상그냥 조용히 처리시켜버리는데, 지금 생각해보니 로그 정도는 남길 수 있을 듯..

  12. 이원구 Avatar

    위와 같은 예제가 C++에서는 RAII를 사용하여 쉽게 처리할 수 있는 부분입니다. 저도 지금 하는 작업에서 SessionGuard라는 RAII 클래스를 사용하는데 대강 다음과 같은 코드가 됩니다.

    SessionGuard sg(psess); // 여기서 session connect

    ErrorCode ret = psess->foo(); // 여기서 예외가 발생하더라도 SessionGuard에 의해 rollback 및 disconnect
    if (ret != SUCCESS) return ret; // 여기서도 SessionGuard에 의해 rollback 및 disconnect

    ret = psess->bar();
    if (ret != SUCCESS) return ret; // 여기서 SessionGuard에 의해 rollback 및 disconnect

    sg.set_commit(); // 여기서 모든 함수가 성공적으로 수행되었음을 SessionGuard에 알림
    return SUCCESS; // scope 빠져나가거나 return 하면서 commit 및 disconnect

    이런 RAII를 사용하게 되면서 더이상 C++에서는 C처럼 SESE(Single Entry Single Exit)를 권장하지 않게 되었습니다. 사실 SESE는 코드의 indentation을 너무 깊게 만드는 경향이 있었죠.

    암튼 GC를 가진 소멸자가 없는 언어들은 이런 RAII 클래스 작성이 불가능한 단점이 있네요.

  13. 공성식 Avatar
    공성식

    민구님 말씀처럼 close()에서 exception이 나는 것은 드물고 (socket error 정도?) 별로 해줄 것도 없을 겁니다.

    일반적으로 에러에 대한 대처법은 다음 중 하나가 될 것입니다.

    1. 에러를 무시한다. (이럴 경우 자신의 caller에게 에러가 그대로 전달)
    2. 에러를 잡아서 처리하고 끝낸다. (silent exception 포함. 자신의 caller에게는 전달 안됨)
    3. 에러를 잡아서 뭔가를 한 후, 다른 에러로 바꿔서 또는 그대로 다시 발생시킨다. (자신의 caller에게 전달)

    그런데 이 중에서 2번 옵션을 선택할 때는 상당히 고민을 해야할 경우가 많습니다.
    Structured exception handling은 마치 조직에서의 보고 체계와 비슷한 것 같습니다.
    Exception은 call stack을 따라 promotion되어야 의미있는 경우가 많은데 중간에서 차단되면 caller의 입장에서 그에 대한 보고를 받을 수가 없죠.
    물론 상위에 보고하지 않아도 될 만큼 사소한 에러라면 상관없지만 그만큼 사소한 에러가 실제로는 별로 존재하지 않는다는 겁니다.

    자바는 checked exception이라는 매커니즘을 통해 이 보고를 체계화하고 강제화하려고 했는데, 많은 프로그래머들이 이를 귀찮게 여겨 silent exception으로 처리하는 경우가 많아 오히려 더 안 좋은 결과를 가져왔다고 생각합니다. 그래서 C#에서는 이를 수용하지 않았구요.

    민구님께서 “통산 그냥 조용히 처리시켜버리신” 까닭은 주로 어플리케이션을 만드셨기 때문이 아닌가 생각합니다. 어플리케이션 개발자는 exception 처리에 관한 최종 결정자이므로 맘대로 결정해도 상관 없겠죠. 그렇지만 library 개발자라면 얘기가 달라질 것 같습니다. 사소한 에러라도 자신의 콜러에게 일일이 보고하고 그에 대해 결정하게끔 해야만 하죠. (만약 안 그러면 보고누락죄라고나 할까요?)

    역시 에러 핸들링은 어렵다는 생각이 드네요.

  14. MKSeo Avatar
    MKSeo

    @이원구: 이야 멋집니다;;

    @공성식: 네. 전 라이브러리 개발의 경험이 적고 애플리케이션 위주였어서 이렇게 생각해왔던거라 생각됩니다. 참고로 제가 제일 못하는 것 두가지중 하나가 예외처리입니다. (다른 하나는 dynamic programming 알고리즘입니다;;) 그런데 C#에 checked exception 이 없어진 까닭에 대해선 전 다르게 알고 있습니다: The Trouble with Checked Exceptions

  15. 공성식 Avatar
    공성식

    뭐, 저도 예외처리를 잘 하는 건 아니구요…- -;;;

    링크로 걸어주신 글에 가 보면 민구님께서 요약해 놓으신 부분에 다음과 같은 게 있습니다.

    ##개발자는 자동적으로 “예외를 나중에 처리하고 지금은 catch clause를 비워둬야겠다”고 생각하게 된다.

    catch clause를 비워두는 건 silent exception이랑 동일한 의미죠?
    저는 그 부분을 말씀 드린 거였습니다.
    물론 그게 C#에서 checked exception을 수용하지 않은 데 대한 충분조건은 아니었지만 필요조건의 하나였던 것 같아요.

    저도 전에 읽었던 글인데 다시 읽어봐도 역시 좋은 글이네요. :-)
    전 프로그래밍 시작을 델파이로 했기 때문에 Anders에 대해 아주 좋은 기억을 가지고 있습니다.
    MS로 옮겨갈 때 약간 우려했지만 역시나 이름값을 하네요.

  16. trax Avatar

    C#의 using 구문을 사용하는 경우는 범위를 벗어나는 경우 IDisposable 인터페이스의 Dispose 메서드를 호출하여 자원 정리를 강제합니다.
    using 구문을 try, catch, finally에 대한 syntax sugar라고 표현할 수 있지만 정확한 것은 아닙니다.
    라이브러리를 개발하는 경우는 프레임워크에서 정한 종류의 예외가 아니면 예외처리를 하지 않습니다. 이는 C, C++의 표준 라이브러리 소스 코드를 뒤져보셔도 확인할 수 있고, C#을 이용할 수 있는 MS의 SSCLI와 Mono 소스 코드를 확인해보셔도 알 수 있습니다.

    SSCLI에서 String.Copy() 메서드는 memcpyimpl()을 호출하며 구현은 다음과 같습니다.
    (memcpyimpl()을 호출하기 전에 매우 기본적인 검사만 있을 뿐 예외처리는 없습니다)

    internal unsafe static void memcpyimpl(byte* src, byte* dest, int len) {

    // Portable naive implementation
    while (len– > 0)
    *dest++ = *src++;
    }

    Linux Kernel의 경우 예외처리는 거의 없습니다. 정확히 말하자면 NULL이 아닌 값이
    전달되었는가 정도의 검사와 있을 수 없는 경우(NULL이 아닌데 NULL인 경우)를 위한
    BUG() 매크로 정도의 정의가 포함되어 있습니다. OS를 개발하는 Linus의 관점에서 보자면
    코드란 정확하게 작성되어야 하며, 정확하게 동작해야 한다입니다. Linus는 이런 이유 때문에
    kdbg와 같은 커널 디버거를 커널에 포함시키지 않고 있습니다.(그가 살아있는 동안은
    커널에 편입될 일이 없을 겁니다)
    디버거야 말로 게으르고, 능력없는 사람들이 사용하는 것이며, 올바른 프로그래머는
    올바른 코드를 작성할 줄 안다고 얘기합니다.

    예제로 든 스택 구현도 설명을 위해 그리 구현된 것일뿐, 그렇지 않게 구현될 수 있다고 봅니다.

    개인적으로는 Exception Handling 보다는 Condition System이 더 낫다고 봅니다.

    생각해보면 Exception Handling은 거의 사용하지 않고 있군요…

  17. MKSeo Avatar
    MKSeo

    답글 감사합니다.. 정말 제경우엔 condition 검사가 모르고 지나칠 버그를 구해준적이 한두번이 아닌듯.

  18. 공성식 Avatar
    공성식

    @trax: trax님 안녕하세요? using이 IDisposable 타입의 경우 try…finally…에 대한 syntax sugar라는 게 정확한 표현이 아니라고 하셨는데 좀더 부연설명을 부탁해도 될까요? 어쩌면 Syntax sugar에 대한 정의가 저와 좀 달라서 그런 것 같기도 하구. 제 생각에 이런 경우 using은 분명 syntax sugar입니다. 왜냐하면 using 구문이 없어도 (약간 불편하지만) 동일한 기능을 구현할 수 있기 때문입니다. 만약 using이 뭔가 새로운 기능을 부여하는 것이라면 using 구문이 없는 다른 닷넷 언어에서는 어떻게 구현할 수 있을까요?

    다음은 C# Specification 15.13에 있는 글을 옮긴 것입니다.

    A using statement of the form

    using (R r1 = new R()) {
    r1.F();
    }

    is precisely equivalent to

    R r1 = new R();
    try {
    r1.F();
    }
    finally {
    if (r1 != null) ((IDisposable)r1).Dispose();
    }

  19. trax Avatar

    지적하신 것이 맞습니다. 용어 사용이 다른 거네요.

    try … catch … finally를 using으로 구현할 수 있으니 syntax sugar입니다.

    제 관점에서 syntactic sugar가 아니라고 한 것은 Dispose() 호출을 자동으로 해주는 것이 아니라는 점입니다. 구문이 그대로 일대일 대응이라면 syntactic sugar라 하겠지만 Dispose()를 호출해서
    자원을 정리해준다는 지식 또는 의도까지 포함된 것은 아니라는 점에서 syntactic sugar가 아니라고 하는 겁니다

    using이 없는 다른 닷넷 언어들은 C#의 spec에 설명된 것처럼 구현할 수 있습니다.
    바꿔말하면 try .. catch .. else… finally나 using 같은 기능이 빈약한 C++의 경우
    RAII idiom을 사용합니다.

    제 관점은 A를 B로 구현할 수 있다고 해서 A를 B의 syntactic sugar라고 안 본다입니다.
    구현의 관점 보다는 a = a + 1에 대해서 a++이나 ++a와 같은 표현식의 제공 같은 것들을
    syntactic sugar로 봅니다.

    C 언어에서 C++의 템플릿 같은 기능을 구현할 수 있으며, 이미 리눅스 커널에서 그런 기법을
    널리 사용하고 있어도 “C++의 템플릿은 C 언어의 매크로와 포인터로 모두 구현할 수 있다”라고 해서 syntactic sugar는 아니라고 보는 관점입니다.
    (커널은 어떤 자료구조에도 관계없이 사용할 수 있는 Linked List, Red-Black Tree, Hashtable 등을 구현하고 있습니다. 알고리즘만을 구현한다는 관점만으로 보면
    템플릿을 써야할 이유가 없죠)

    공성식님이 얘기하신 syntactic sugar와 제가 생각하는 syntactic sugar라는 용어의 의미가 조금 다르네요. ^^;

    맞는 비유인지 모르지만,

    while 문으로 100% 구현할 수 있지만, 아주 가끔 do while의 형태가 유용할 때가 있기 때문에
    대부분의 언어들은 이를 추가합니다.

    공성식님을 비롯해서 대부분의 분들은 do .. while의 형태도 syntactic sugar로 볼 것입니다.
    (맞나요?)
    복잡해 보이지만 while로 do .. while의 형태를 구현할 수 있습니다. 대부분의 분들은
    do … while을 syntactic sugar로 보지만 저는 그렇지 않습니다.
    while로 구현할 수는 있지만 그 idiom을 학습하기엔 너무 복잡합니다.

    손님에게 메뉴를 먼저 출력하고 선택을 묻는 코드를 do .. while로 작성하고
    이를 while 형태로 바꿔보라고 하면 다들 헤매일 것입니다.

    반면에 for 문을 while 문으로 바꿔보라고 하면 어려워하는 사람이 없습니다.
    모든 for 문은 while 문으로 쉽게 변환할 수 있으니, 이 관점으로 보자면 저는 syntactic sugar라
    합니다. 알아야 할 내재된 지식이 없으니까요.
    그러나, 반대로 모든 while 문을 for 문으로 옮길 수 없습니다.
    때문에 저는 for와 while 문의 관계도 syntactic sugar로 보지 않습니다.

    if .. else if… else로 모두 구현할 수 있지만 코드를 깨끗하게 해주는데 유용한
    switch case문을 대부분의 언어는 도입합니다.
    불행히도 if …문을 switch 문으로 100% 변환할 수 없습니다.(일부 언어는 이게 가능하도록
    case 문에서 range나 다중 조건을 묶을 수 있습니다. 다중 조건은 C 언어 등의 fall through로
    구현할 수는 있습니다)

    많은 분들이 if … else와 switch case를 syntactic sugar로 봅니다. 저는 이게 옳지 않은 거라 봅니다. 둘이 표현하는 범위가 다르고, 표현력이 다릅니다.

    *(a + 1)을 a[i]과 같이 표현하게 해주는 포인터 첨자 연산자 []는 syntactic sugar입니다.

    http://en.wikipedia.org/wiki/Syntactic_sugar

    A라는 표현을 B로 축약할 수 있어는 Syntactic Sugar지만
    A를 B로 구현할 수 있어는 Syntactic Sugar가 아닙니다. 가 제 관점입니다.

  20. MKSeo Avatar
    MKSeo

    @trax: 흠 그렇군요.. 저도 사실 궁금했음, 위키에는 expresiveness, 또는 easily translated의 용어로 설명하는데 이 중 expresiveness는 굉장히 엄밀한 의미로 봐서는 잘못 쓴 단어 같습니다. 가령, relational algebra와 sql간의 expresiveness power를 이야기할때는 하나가 할 수 있는일을 다른 것으로 할 수 있는가를 따지죠. 이와 같은 맥락으로 본다면 사실상 폰노이만에 바탕을 둔 모든 프로그래밍언어는 turing machine을 구현할 수 있으므로 그들의 expresiveness power는 같다고 볼 수 있고, 따라서 모든 언어의 대부분의 구성요소가 서로서로 syntactic sugar라고 불려버릴 듯.

    두번째 용어는 easily translated인데, 이건 그냥 각자의 감인거 같아요. 그래서 syntactic sugar의 개념이 무척 모호하게 느껴지네요. 물론 trax님이 생각하는 syntactic sugar가 어떤것인지 감으로는 와닿지만 말이죠.

    사족인데, 커널을 공부하셔서 그런지 C로 C++ 템플릿처럼 코딩하기도 다 이미 알고 계시는군요…. ㅎㅎ 저는 그 사실을 친구가 “C에서 매크로를 써서 컴파일 타임에 바인딩할 수 있는거 알아?” 뭐 그런 얘기를 해서 몇주전에 알게된건데 말이죠;; 음 다들 대단~.

  21. 공성식 Avatar
    공성식

    trax님, 부연설명 감사합니다.
    사실 어디까지를 syntactic sugar라고 해야 할지 참으로 애매한 면이 있습니다.
    말씀하신 do…while 구문의 경우엔 저도 단지 syntactic sugar라고 생각하지 않습니다.
    오히려 semantic spice라고 해야 할까요.
    신택스가 줄었다거나 보기 좋아졌다기보다는 새로운 의미를 부여하니까요.

    그런데 using의 경우엔 저는 대표적인 syntactic sugar라고 생각합니다.
    만약 이게 없었다면 늘 메소드 내에서 사용되는 IDisposable 오브젝트에 대해서는 다음과 같은 boilerplate 코드가 반복될 겁니다.

    R r1 = new R();
    try {
    r1.F();
    }
    finally {
    if (r1 != null) ((IDisposable)r1).Dispose();
    }

    코드의 내용과 관계없이 위의 틀을 먼저 만들어놓고 시작하곤 하겠죠.
    그런데 사실 IDisposable 타입의 오브젝트는 무척 많이 사용됩니다.
    모든 윈도우 컨트롤들이 그렇고, 파일이 그렇고, 폰트, 소켓, DB 커넥션 등등 너무도 많은 것들이 IDisposable입니다.
    그렇다고 해서 이걸 자동으로 프레임워크 수준에서 해결해 주기도 어렵고 하니 아쉬운 대로 제공한 방법이 바로 using이 아닐까 생각합니다.
    그러니까 탄생부터 syntactic sugar인 셈이죠.

    제 생각에, 어떤 것이 syntactic sugar인지 아닌지를 판단하는 가장 좋은 기준은 standard spec 이라고 생각합니다.
    어차피 implementation은 각 vendor들마다 조금씩 다를 수 있기 때문에 서로 다른 신택스를 이용하여 컴파일된 코드가 동일한지 아닌지의 여부를 가리긴 곤란할 것 같습니다.
    그런데 using의 경우처럼 spec에서 명백히 “is precisely equivalent to”라는 문구를 써서 같은 의미라고 말한 경우 우리는 “안전하게” syntactic sugar라고 할 수 있지 않을까요.

    trax님께서 “제 관점에서 syntactic sugar가 아니라고 한 것은 Dispose() 호출을 자동으로 해주는 것이 아니라는 점입니다”라고 말씀하신 것은 어떤 의미로 말씀하신 것인지 잘 모르겠습니다.
    using 구문은 분명히 Dispose()를 호출하거든요 (에러가 발생하든 안 하든 관계없이).
    using 구문은 semantically 어떤한 기능 추가나 변경도 없다고 생각합니다.

    trax님의 용어 사용에 태클을 걸려는 것은 아니구요.
    다만, 관점의 차이가 큰 것 같아 서로 의견을 교환해 보려는 의도였습니다.

    감사합니다.

  22. trax Avatar

    “is precisely equivalent to”라는 표현은 syntactic sugar라고 표현하는데 충분조건에 불과합니다.

    a = a + 1을 a++로 표현하는 것
    *(a + 1)을 a[i]로 표현하는 것

    과 같이 번거로운 것들을 줄여주는 것, 선택적으로 사용할 수 있는 것을 Syntactic Sugar로 생각합니다.(이 역시 모호한 정의지만)

    A를 B로 구현할 수 있는 것을 많은 분들이 “Syntactic sugar”로 지칭하고 있는데,
    용어의 남용일 뿐이라 생각합니다.

    using 문은 try … catch … finally로 구현이 되므로 syntactic sugar라고 하는 것은
    do … while 문은 while 문으로 구현이 되므로 syntactic sugar라 하는 것과 차이가 없습니다.
    (프로그램의 동작에는 전혀 차이가 없으며 이 역시 “is precisely equivalent to”입니다)

    MSDN에서 소켓 관련 예제 뿐만 아니라 대부분의 예제는 using 문을 사용했을 때
    변환되는 것처럼 Dispose()를 호출하지 않습니다.

    코드 내에 숨겨진 의도를 파악해야 하는 것은 “Syntactic sugar”가 될 수 없습니다.

    A를 B로 표현할 수 있는 것은 “Syntactic sugar”이지만
    A를 B처럼 구현할 수 있는 것은 “Syntactic sugar”가 될 수 없다가 제 관점입니다.

    대부분의 분들은 A를 B처럼 구현할 수 있다를 “Syntactic sugar”로 부르고 있으며,
    개인적으로는 용어의 남용이라 생각합니다.

    PHP에서 POST 폼을 처리할 때 $HTTP_VARS_POST[ ‘name’ ] 대신에 $_POST[ ‘name’ ]과 같은
    형태를 사용할 수 있는 것은 Syntactic sugar이지만,
    목록을 처리하기 위해 리스트처리를 하는 방법 A와 방법 B가 있고, 동일한 동작을 보여주지만
    이를 Syntactic sugar라 하지 않는 것과 같습니다.

    using 문을 try … catch … finally로 변경하려면 개발자는 기본적인 틀을 작성할 줄 알아야하고,
    Dispose() 메서드를 호출해야 한다는 지식을 갖고 있어야 합니다.
    (scope도 변화하겠지만)
    즉, 방법 A(using사용)와 방법 B( try … catch … finally)는 같은 동작을 보여주겠지만
    Dispose() 호출과 같이 코드에 숨겨진 의도가 있는 한,
    방법 A와 방법 B를 동일하게 동작한다는 이유만으로 Syntactic Sugar라 보지 않는다는 관점입니다.

    단순히 A를 B로 자동으로 언어에서 변환한다는 표현의 관점(?)으로 본다면
    Syntactic sugar라고 부르는 것도 이해하지만, 전 그런 관점에서 Syntactic sugar라는
    용어를 언급하는 것이 용어의 남용이라 생각합니다.

  23. 공성식 Avatar
    공성식

    trax님의 정의를 따르자면 syntactic sugar의 범위가 무척 좁아질 것 같네요.
    (아주 짧막한 expression 정도?)

    원래 syntactic sugar가 좀 주관적인 개념이다 보니 그럴 수도 있다고 생각합니다.
    저도 공식적으로 “이것이 syntactic sugar다” 라고 자신 있게 말할 수는 없겠지만, 대략 이런 기준을 갖고 있습니다.

    A가 B의 syntactic sugar일 경우 다음의 조건을 모두 충족해야 합니다.
    1. A와 B는 semantically 동일하다.
    2. A를 만든 목적이 B를 간편하게 표현하기 위함이다. 즉, A는 없어도 그만이지만 있음으로써 좀더 편하게 프로그래밍할 수 있다.

    저는 C#에서 using 구문이 위의 두 조건을 모두 충족한다고 생각합니다.

    혹시 오해가 있을까봐 다시 말씀드리자면 using은 일반적인 (try…finally…)에 대한 syntactic sugar가 아니라 더 구체적으로 다음과 같은 경우에 대해서만 syntactic sugar입니다.

    R r1 = new R();
    try {
    r1.F();
    }
    finally {
    if (r1 != null) ((IDisposable)r1).Dispose();
    }

    물론 IDisposable 오브젝트를 꼭 위와 같이 사용하지만은 않습니다.
    오브젝트의 life-span에 따라 container object의 constructor에서 생성하고 finalizer에서 Dispose할 수 있겠죠.
    이럴 경우엔 using 구문을 사용할 수 없죠.
    그러므로 이런 경우는 논외가 되겠습니다.
    마찬가지로, 예로 드신 Dispose를 호출하지 않는 경우와 비교하는 것도 의미가 없을 것 같습니다.

    이런 관점에서 저는 C#의 property를 Java의 getter/setter에 대한 syntactic sugar라고 부르는 것도 무방하다고 생각합니다.

  24. MKSeo Avatar
    MKSeo

    @공성식: property가 getter/setter에 대한 syntactic sugar라는 새로운 포문을 여셨군요;;

    저는 syntactic sugar라는 표현을 지금까지 주관적으로 써왔습니다만, 문법적으로는 그게 그거처럼 보일지 몰라도, property는 public field 를 가지고 코딩했다가도 나중에 추가적인 동작(예를 들어 get할때 defensive copying, set하기전에 올바른 값인지 확인)을 추가할 수 있는 강력한 도구입니다. getter/setter에 대한 키보드 몇개 덜 누르는 효과로 평가절하하기엔..

    자바로 코딩해보셨으면 아시겠지만 getter/setter는 OOP의 이름아래 때론 코드에 get, set 메소드가 난무하는 복잡한 결과를 초래하기도 합니다. 분명히 property형태의 코딩이 더 나은점이 있고, 그래서 @property라는 annotation이 자바에 추가될 것으로 예견되기도 했습니다. (결과적으로는 안된걸로 알고 있지만요.) 만약 property가 문법적 단축효과만 있는거라면 C#따라한다는 모욕을 받을 일이 분명한 것이 추가될거라고 다들 이야기하지는 않았을 듯…

  25. 공성식 Avatar
    공성식

    @MKSeo: 아, 민구님도 이야기에 동참을 하시는군요. 재밌게 됐습니다…:-)

    ———-
    property는 public field 를 가지고 코딩했다가도 나중에 추가
    ———-

    이것은 property를 잘못 이해하는 대표적인 예입니다.
    public field를 public property로 만드는 것이 안 되는 경우가 많거든요.
    왜냐하면 데이터에 접근하는 코드와 메소드를 호출하는 코드는 다르기 때문입니다.

    만약 어떤 데이터를 외부로 공개하려면 public field를 만들지 말고 private field로 만든 후에 public property를 통하여 접근하게 하여야 합니다.
    (설사 get/set에서 아무런 처리를 안 한다고 하더라도…)
    민구님 말씀 대로 나중에 어떤 기능을 추가하면 자연스럽게 transition이 될 것 같지만 꼭 그렇지는 않습니다.
    예를 들어 어떤 컴파일된 라이브러리가 있고 어플리케이션에서 그 라이브러리의 public field를 이용했다고 해보죠.
    나중에 만약 라이브러리 개발자가 public field를 public property로 바꾸었다고 하면 그 라이브러리를 사용하는 어플리케이션에서는 에러가 납니다.
    이럴 경우 어플리케이션을 재컴파일해야만 합니다.
    왜냐하면 최초의 컴파일 시에는 public field인 데이터에 접근했지만 나중에는 public property에 접근해야 하는데 사실상 property는 메소드 호출의 형태로 코드가 만들어지거든요.
    (필드와 메소드(property)는 바인딩하는 방법이 다르지요)
    즉, public field -> public property 의 전이가 자연스럽게 이뤄지지 않아 IL 코드상에서 호환이 되지 않습니다.
    그래서 닷넷에서 제시한 가이드에 보면 모든 필드는 private/protected 로 만들고 반드시 property를 이용하라고 합니다.
    그래야만 나중에 코드를 추가해도 문제가 안 생기거든요.
    물론 자신이 모든 소스를 다 가지고 있을 경우에는 별 문제가 안 되겠지만 대부분의 경우 다른 라이브러리에 많이 의존하게 되죠.

    ————
    자바로 코딩해보셨으면 아시겠지만 getter/setter는 OOP의 이름아래 때론 코드에 get, set 메소드가 난무하는 복잡한 결과를 초래하기도 합니다.
    ————

    이 문제는 property의 경우도 마찬가지입니다. 쓸데없이 외부로 많은 것을 공개하면 로직이 내부가 아닌 외부에서 만들어지는 결과를 초래해서 객체지향의 원뜻을 저해하게 되죠. 가급적 최소한의 것만 외부로 공개하는 것이 좋을 것 같습니다.

    혹시 getter/setter가 해결하지 못하는 문제를 property가 해결하는 게 있다면 예를 들어주시면 고맙겠습니다. 만약 syntactic sugar 이상의 기능을 제공하는 케이스가 있다면 저도 다시 생각해 봐야겠습니다.

    PS: 근데 public field를 만드는 경우도 있나요? 코드 라인 수는 줄을지 모르지만 사실상 굉장히 위험하고 Anti-OOP적인 것 같아요. 전 그래서 루비의 철학이 맞는 것 같아요. 모든 필드는 private이잖아요. 외부로부터는 메시지만 받지 직접 필드에 접근하는 것은 원천봉쇄를 하는 거죠.

  26. MKSeo Avatar
    MKSeo

    @공성식:
    1. public 에서 property로 바꾸는 경우
    – 제가 이해를 잘 못 한건지;; 컴파일을 해야한다는것이 문제란 말씀인가요? 음. 하나의 apps바깥으로 나가는 경우라면, 그래서 내 라이브러리를 특정 위치로 copy, paste해서 곧바로 돌아가게 해야하는 필드들이라면 처음부터 public으로 해서는 안될 듯합니다. 하지만 그 외의 경우라면 컴파일만 새로 하면 될 것 같은데요;;

    2. syntactic sugar이상의 역할을 하는 경우
    – 갑자기 예를 들라니까;; 한줄에 get, set만 대여섯개 쓰는 코딩이 지겨웠었죠. 왜 그냥 foo.bar 해서 쓰면 안될까..라는 생각이 절로 들게되었습니다.

    3. public field로 만드는 경우
    – 저는 웹 프로그래밍을 하도 많이해서;; 간단한 예는 VO가 있습니다. 값 객체를 갖고 왔다갔다 하는데 이것을 굳이 getter, setter로 해야할 이유가 없는 것이죠. 그리고 저는 OOP원칙에 별로 안충실합니다;; 협업의 경험이 적어서 그런지 모르겠지만, 필요하면 그냥 구조체처럼 씁니다.
    – 두번째로, getter/setter는 값을 validation 할 수는 있지만 내부 필드라는 구현에 여전히 의존합니다. 사실은 메소드를 통해서 ‘네가 이걸 해줬으면 좋겠다”라고 하는 것이 보다 더 바람직한 방법이죠. public 필드가 없어지거나 동작이 바뀌나요? 그럼 에러가 나겠죠. 내부 필드가 int에서 long으로 바뀌었나요? 그럼 getter, setter도 다 깨집니다. 사실은 크게보면 그거나 그거나 일 듯.
    – “일어나리라고 생각한 일은 일어나지 않는다”를 따라서, 지나친 추상화를 전 경계합니다. 하다보면 추상화만 하다가 세월아 네월아하는 경우를 몇번 겪다보니, 이젠 오히려 필요하면 추상화하는 쪽으로 접근하고, 그것이 getter/setter를 피하게 되는 이유가 되고 있습니다. 음 여기에서의 룰은 – 리팩토링과 XP를 따라서 – 2번까지는 반복한다. 3번째 반복하게 되면 그 때 추상화한다를 따릅니다.

    4. Ruby는 필드를 원천 봉쇄함
    – 알고 계시겠지만.
    class Foo; def initialize(val); @bar= val; end; end
    Foo.new(3).instance_eval { p @bar }
    결과: 3

    루비만큼 해커의 언어도 없다니까요;;

  27. 공성식 Avatar
    공성식

    @MKSeo: 민구님, 금방 답을 주셔서 감사합니다. 잠시 밖에 나가 조깅하고 돌아오니 벌써 리플이 올라와 있네요…:-)

    1. public 에서 property로 바꾸는 경우

    http://www.codinghorror.com/blog/archives/000654.html
    를 읽어보시면 비교적 자세히 나와 있습니다.

    저는 예를 하나 들겠습니다.
    민구님께서 어떤 어플리케이션(MKSeo.cs)을 만들어서 판다고 가정해 보죠.
    그런데 MS에서 제공하는 라이브러리(MSLib.dll)의 다음과 같은 클래스를 이용합니다.

    class C {
    public string Name;
    }

    민구님은 다음과 같이 코딩을 할 겁니다.
    C obj = new C();
    obj.Name = “MKSeo”;

    그런 후 MSLib.dll을 reference로 지정하여 MKSeo.cs를 컴파일하여 MKSeo.exe를 만듭니다.
    물론 이때 MSLib.dll은 컴파일시 참고만 할 뿐이며 실제 링크되는 것은 아닙니다.
    이제 MKSeo.exe를 고객에게 판매합니다.
    이때 MSLib.dll은 민구님이 직접 고객에게 제공하는 것이 아니라 이미 MS로부터 다운로드 받아 고객의 컴퓨터에 설치돼 있습니다.
    그런데 어느날 MSLib.dll의 내용이 다음과 같이 바뀌었다고 합시다.

    class C {
    private string name;
    public string Name {
    get { return name; }
    set { name = value; }
    }
    }

    인터페이스 상으로는 변화가 없어 보이죠.
    그렇지만 이렇게 MSLib.dll이 변하게 되면 MKSeo.exe는 실행시 에러가 납니다.
    필드와 바인딩되도록 만든 코드는 property와 바인딩이 될 수 없기 때문입니다.
    (breaking change)

    좀 길었습니다만 설명이 잘 되었길 바랍니다.

    2. syntactic sugar이상의 역할을 하는 경우

    ————
    – 갑자기 예를 들라니까;; 한줄에 get, set만 대여섯개 쓰는 코딩이 지겨웠었죠. 왜 그냥 foo.bar 해서 쓰면 안될까..라는 생각이 절로 들게되었습니다.
    ————

    단지 코딩하기 편하기 위해서라면 전형적인 syntactic sugar라고 할 수 있겠네요.
    사실 저도 처음 언급할 때 “~라고 해도 무방하다”고 완곡하게(?) 말씀 드린 것은 property를 옹호하는 사람들에게 단지 코딩의 편함 이상의 뭔가가 있다는 느낌(?) 때문입니다.
    필드와 코드를 통합하려는 일종의 “코딩 철학적 운동”이랄까요.
    Property를 이용하여 person.Age++ 와 같은 자연스러움을 메소드에 적용하자는 거죠.
    person.getAge()++ 는 안 되죠.

    3. public field로 만드는 경우

    ————
    저는 웹 프로그래밍을 하도 많이해서;; 간단한 예는 VO가 있습니다. 값 객체를 갖고 왔다갔다 하는데 이것을 굳이 getter, setter로 해야할 이유가 없는 것이죠. 그리고 저는 OOP원칙에 별로 안충실합니다;; 협업의 경험이 적어서 그런지 모르겠지만, 필요하면 그냥 구조체처럼 씁니다.
    ————

    글쎄요… 이건 뭐 굳이 안 된다라기보다는…
    사실 전 MS Framework Library를 비롯하여 Production Quality 코드에서는 public field를 한번도 본 적이 없습니다.
    그렇지만 개인적인 프로젝트에서야 뭐 상관 없겠죠.
    만약 단지 편하기 위해서라면 매크로를 이용하여 Property를 쉽게 만드는 것도 방법일 것 같구요.

    ————
    두번째로, getter/setter는 값을 validation 할 수는 있지만 내부 필드라는 구현에 여전히 의존합니다. 사실은 메소드를 통해서 ‘네가 이걸 해줬으면 좋겠다”라고 하는 것이 보다 더 바람직한 방법이죠. public 필드가 없어지거나 동작이 바뀌나요? 그럼 에러가 나겠죠. 내부 필드가 int에서 long으로 바뀌었나요? 그럼 getter, setter도 다 깨집니다. 사실은 크게보면 그거나 그거나 일 듯.
    ————

    property는 IL 코드로 만들어졌을 때 getter/setter와 아주 동일한 코드를 만듭니다.
    그러므로 서로의 장단점은 논할 여지가 없을 것 같구요.
    public field는 1번에서 말씀드린 대로 breaking change의 문제점이 있으므로 조심하는 게 좋을 것 같구요.
    그리고 말씀하신 대로 어떤 오브젝트가 데이터를 밖으로 직접 노출시키기보다는 그 데이터로 해야할 일들을 메소드로 공개하고 데이터는 가급적 숨기는 게 좋겠죠.
    안 그러면 C의 구조체처럼 될 테니까요.

    ————
    “일어나리라고 생각한 일은 일어나지 않는다”를 따라서, 지나친 추상화를 전 경계합니다. 하다보면 추상화만 하다가 세월아 네월아하는 경우를 몇번 겪다보니, 이젠 오히려 필요하면 추상화하는 쪽으로 접근하고, 그것이 getter/setter를 피하게 되는 이유가 되고 있습니다. 음 여기에서의 룰은 – 리팩토링과 XP를 따라서 – 2번까지는 반복한다. 3번째 반복하게 되면 그 때 추상화한다를 따릅니다.
    ————

    이 점에는 저도 동의합니다.
    다만 public field 대신에 property나 getter/setter를 이용하는 것을 추상화라고 해야 할지에 대해서는 잘 모르겠습니다.

    4. Ruby는 필드를 원천 봉쇄함

    예외는 있는 거죠 뭐…쩝.
    다만 코드에 다음과 같은 주석을 달아주세요.
    “어린이는 절대 따라하지 마세요.” ;-)

    민구님 블로그가 무척 유익한 즐거움을 주네요.

  28. MKSeo Avatar
    MKSeo

    @공성식: “다만 public field 대신에 property나 getter/setter를 이용하는 것을 추상화라고 해야 할지에 대해서는 잘 모르겠습니다.”에 대해, 저를 헤비 C언어 프로그래머라고 불러주세요;;;;

    남들은 다 setter/getter를 쓰며 사는군요. 정말 몰랐습니다..

  29. MKSeo Avatar
    MKSeo

    참 그리고.. sam kong님 이제 블로깅은 접으셨나요?

  30. trax Avatar

    ——————–cut here————————
    using System;

    class App
    {
    private int counter;

    public int Counter
    {
    get
    {
    return counter;
    }
    set
    {
    counter = value;
    }

    }

    public static void Main( string[] args )
    {
    App app = new App();
    app.Counter = 200;
    Console.WriteLine( app.Counter );

    app.Counter++;
    Console.WriteLine(app.Counter);

    }
    }
    ——————–cut here————————

    간단한 예제입니다. C#에서는 Smart Field를 도입하고 있으며 C++, Java 같은 언어들의
    getter/setter를 대신하려 합니다.

    accessor methods를 field 형태로 캡슐화하는 것입니다. 공성식님은 이를 Syntactic sugar라
    본다고 하지만,
    위 예제에서 app.Counter++과 같은 표현식을 직접 사용할 수 있는 것(공성식님이 위에서 언급한 Syntactic sugar 이상의 예)은
    표현의 범위를 넓혀줍니다.

    C#에서 accessor methods 사용은 선택적인 거라 봅니다.

    Smart field는 언어의 기능이지 accessor methods에 대한 Syntactic sugar라 보지는 않습니다.
    Smart field를 사용할 때와 accessor methods를 사용할 때의 표현 방법이나 코딩 방법은
    다르다고 보기 때문입니다.

    매크로와 프리 컴파일을 통해서 try … catch … finally를 C에서 구현할 수 있고,
    실제로 그렇게 사용하고 있습니다.(유명한 TRY … CATCH … FINALLY가 있음)
    C++에서는 try … catch를 제공하며 이는 해당 언어의 기능일 뿐이죠.
    C에서는 try … catch 없이도 이미 그런 기능을 스스로 만들어서 사용하고 있습니다.(커널이 대표적인 예. 언제든 스택 덤프를 만들어 내고 죽지요)
    C에서 이건 다 이렇게 구현해서 쓰고 있고, C++에서도 구현해서 쓸 수 있으니 C++의
    try .. catch는 Syntactic sugar야… 라고 해야할까요?

    커널 코드를 보면 C 언어에서 구조체를 이용해서 광범위하게 인터페이스를 사용하며,
    각 계층 구조를 만들어 사용합니다.(n-tier 구조처럼)
    그러면 자바의 interface, C#의 interface, c++의 추상 클래스는 전부 Syntactic sugar라
    할까요?

    C#의 Smart Field는 자바의 accessor methods와 표현만 놓고보면 같다고 얘기하시고
    Syntactic sugar라고 보신다고 하는데…. 이 역시 용어의 남용이라고 보는게 제 관점입니다.
    (app.Counter++와 같은 표현은 보다 높은 수준의 추상화를 제공한다고 보는데 말이죠)

    A를 B로 표현할 수 있는 표현의 관점에서만 Syntactic sugar라 논해야 합니다.
    A를 B처럼 구현할 수 있다는 관점에서 Syntactic sugar라 명명하면
    Syntactic sugar가 아니라고 할 수 있는 게 거의 없습니다.

    Syntactic sugar가 가득한 언어를 찾자면 Perl이겠죠. 같은 함수를 갖고도 코딩하는 방법을
    전혀 달리할 수 있습니다. 구문을 선택해서 사용할 수 있습니다. $_ 같은 다양한 내장변수의
    개념을 이용해서 a = func(); 형태의 코딩을 func() 형태의 코딩으로 선택할 수 있는 게
    널려있으니까요.

    문법상의 단축효과만 Syntactic sugar라 봐야 합니다.

    공성식님의 관점대로면 C#의 Smart Field 뿐만 아니라 Indexer도 Syntactic sugar에 불과하겠네요.

    관점의 차이는 충분히 인지했습니다.

  31. 공성식 Avatar
    공성식

    @trax:
    app.Counter++ 는 app.setCounter(app.getCounter() + 1) 에 대한 syntactic sugar 아닌가요?
    a++이 a = a + 1에 대한 syntactic sugar라고 말씀하셨듯이 이것도 동일한 논리 아닌가요?

    제 생각엔 indexer도 syntactic sugar라고 생각합니다.
    저는 trax님에 비해 약간 넓은 의미로 syntactic sugar라는 용어를 사용하고 있습니다만,
    일반적인 관점에서는 비교적 중도의 입장이 아닌가 생각합니다.
    어떤 사람들은 닷넷 자체가 Win32에 대한 syntactic sugar라고 극단적으로 확장하기도 하니까요.

    그래서 이렇게 애매모호한 용어는 다른 사람이 어떻게 사용하는가를 살펴봅니다.
    어차피 용어라는 게 커뮤니케이션을 하기 위한 것인니 General Consensus 필요하잖아요.
    그래서 제가 이 문제를 뉴스그룹에 올려놓고 사람들의 의견을 물어보고 있는 중입니다.
    현재까지는 대부분의 사람들이 syntactic sugar라고 생각하네요.

    http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_frm/thread/4399aef7468ed95f/36fba9ddaae10dd4?lnk=arm#36fba9ddaae10dd4

    @MKSeo: 예, 제 블로그 닫았습니다. 워낙 관리를 안 해서 민망스러워서요. 레일즈로 홈페이지 하나 만들어야겠다는 생각은 해 왔지만서도 워낙에 게을러서리… 예전에 운영하던 홈페이지 하나는 거의 죽은 채로 있습니다. samanne.net 입니다.

  32. MKSeo Avatar
    MKSeo

    말씀드렸지만, syntactic sugar에 대한 정의가 여지껏 모호해보입니다. 저는 솔직히 두분의 입장에 몇개는 찬성 몇개는 반대이지만, 어떤 의견도 단지 주관적인 생각을 덧붙이는 것만 될 뿐이라 생략하려 합니다.

    아무런 정의도 못내리고 합의만 구하려 시도한다면, 모든 컴퓨터 언어를 튜어링 머신의 syntactic sugar라고 할 수도 있고, 또 반대로 개별언어의 특징을 잘 이해하는 사람은 분명한 차이를 느낌으로 알고 모든게 서로 다르다고 주장할 수도 있어보입니다.

    어쩌면 consensus가 부재한 것이, 애초에 이 단어가 엄밀한 의미를 가지고 시작한 것이 아니어서 인 듯 합니다. 차라리 한가지일을 하는 하나의 방법만 있는 경우 – 예) using 없이 매번 try-catch – 와 한가지일을 하는 여러 방법이 있는 경우 – 예) ruby! – 와 같은 문제는 흥미로운 논쟁거리겠지만, app.Counter++이 syntactic sugar로 정의되는가 안되는가와 같이 아무도 정의 안해준 용어를 사례 중심으로 동의를 얻어가려는 방향은 뭐랄까, 결과물이 나올거 같지는 않습니다.

  33. CN Avatar

    checked exception 무용론도 요즘 꽤나 크게 일고 있는 것 같더군요. 어떤 도구든지 잘 이해하고 유행을 배워야 하는 것 같습니다.

Leave a Reply

Your email address will not be published. Required fields are marked *