디슈가링(Desugaring)을 이용한 foreach의 이해

프로그래밍 언어는 나날이 복잡해지고 있고 우리가 사용하고 있는 프로그래밍 언어의 의미(semantics)를 명확히 이해하기도 점점 어려워지고 있습니다. C#은 2000년에 첫 버전이 나온 후 지난 15년간 일일이 나열하기도 힘들 만큼 수많은 기능들을 추가해왔습니다.

이 글에서는 프로그래밍 언어의 의미를 쉽게 이해하고 사용하기 위한 방법으로 디슈가링(Desugaring)이란 개념을 소개하고자 합니다. 한국말로 직역하면 “무설탕” 혹은 “설탕은 빼주세요” 정도가 되는 디슈가링은 프로그래밍 언어의 새로운 기능을 기존에 알고 있는 다른 기능으로 풀어서 해석하는 방법을 말합니다. (또한 실제로 컴파일러 작성 시 새로운 기능을 기존 기능의 조합으로 구현하는 방식을 말합니다.)

디슈가링을 이용해 C# foreach 문의 의미를 설명해 봅시다. 아래 코드는 IEnumerable 인터페이스를 구현한collection에서 ElementType 타입의 원소를 하나씩 꺼내와서 statement를 실행합니다.

foreach (ElementType element in collection) statement

혹은 아래와 같이 while 문으로 풀어서 설명할 수 있습니다.

E enumerator = (collection).GetEnumerator();
try {
   while (enumerator.MoveNext()) {
      ElementType element = (ElementType)enumerator.Current;
      statement;
   }
}
finally {
   IDisposable disposable = enumerator as System.IDisposable;
   if (disposable != null) disposable.Dispose();
}

우리가 while, 캐스팅, try/finally, IDisposable의 의미를 명확히 이해하고 있다면 이 코드만으로 foreach문이 어떻게 동작하는지 100% 정확히 설명할 수 있습니다.

말로 풀어 보면, IEnumerable 인터페이스를 구현한 collectionGetEnumerator() 메소드를 호출해서Enumerator를 얻어옵니다. 여기에 MoveNext() 메소드가 false를 리턴할 때까지 while문을 돌면서enumerator.CurrentElementType으로 캐스팅하여 statement를 실행합니다. 이 과정에서 예외가 발생할 수 있으므로 while 루프를 try/finally 블록으로 감싸주고, finally 블록에서는 enumeratorIDisposable 인터페이스를 구현했는지 확인하여 Dispose 메소드를 호출합니다.

이는 C# 컴파일러가 실제로 foreach 문을 컴파일하는 방법이기도 합니다. IL 코드를 비교해 보면 foreach를 사용한 코드와 위와 같이 while문을 사용한 코드가 정확히 일치하는 것을 확인할 수 있습니다.

이런 접근 방법은 복잡한 프로그래밍 언어의 기능을 이해하는데 무척 효과적입니다. C# 언어 기능의 대부분은 .NET 런타임의 변경 없이 컴파일러 단에서 디슈가링만으로 구현하기 때문입니다. 같은 방법으로 LINQ, 확장 메소드(extension method), 이터레이터(yield), async 등 여러 C#의 기능들을 이해할 수 있습니다.

One thought on “디슈가링(Desugaring)을 이용한 foreach의 이해

  1. Pingback: 디슈가링(Desugaring)을 이용한 foreach의 이해 | 서광열의 C# 스쿨

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s