매크로 나쁘다.

주의: 이 글은 컴퓨터 세계의 세 종교(운영체제, 프로그래밍 언어, 에디터) 중 하나에 대해 이야기한다. 이들의 선택은 어디까지나 선호의 문제이며 이곳에 적힌 내 생각은 많은 오류를 포함한다.

최근 매크로에 관심이 생겨 Lisp을 보다가 조금 당연한 결론에 도달했다.

매크로는 역시나 나쁘다.

매크로가 없는 언어는 거의 없다. C나 C++같은 언어는 문자열 치환으로 이를 구현했고 OCaml은 AST 수준 매크로를 도입했다. Lisp 계열 언어는 S-expression 문법의 단순함 덕분에 더욱 강력한 매크로 기능을 지원한다.

언어의 확장

이들 매크로를 이용하면 그 기능에는 약간씩 차이가 있지만 결국 하고자 하는 것은 같다. 주어진 언어 문법으로 예쁘게 표현하기 어려운 부분을 매크로로 표현하는 것이다. 예를 들면 C99 이전 C에서는 함수 inline을 흉내내기 위해 매크로를 썼다. OCaml에서는 모든 타입에서 일반적으로 동작하는 compare 함수 정의에 매크로를 쓴다. 가진 것이 오직 리스트와 함수 호출밖에 없는 Lisp에서는 다른 문법 구조들을 추가할 때 매크로를 쓴다. 결국 하고자 하는 것은 언어의 '자유로운' 확장이다.

언어의 확장이 자유롭다니 왠지 멋지다. 😎 이것이야말로 스스로 진화하는 컴퓨팅(AI)의 뿌리 아닌가!

하지만 나는 이것이 매크로의 가장 큰 문제라고 생각한다. 정확히는 언어의 '동적 확장'에 반대한다.

가독성 문제

제 멋대로 확장된 언어로 짜여진 프로그램은 읽기 어렵다.

자유롭게 언어를 확장하며 프로그래밍을 하는 사람은 그 'hacky한' 아름다움에 감동할지도 모르지만 다른 사람은 그 코드를 읽기 위해 새로운 언어를 배워야 한다. 그것이 표현력 부족한 언어를 위해 매크로가 제공하는 것이니까. 종종 Lisp을 보고 간단한 언어라 부르는 이유는 단지 프로그램 작성이나 실행 전에 필요한 모든 문법이 아직 정의되어 있지 않았기 때문이지 정말 리스트와 함수 호출만으로 문법 확장 없이 모든 걸 간결하게 표현할 수 있기 때문이 아니다.

언어 확장성 vs 가독성

내 마음 속 일 번은 가독성이다. 아이러니하게도 매크로가 등장한 배경도 가독성이다. 두둥! 언어의 문법적 한계에서 오는 코드 중복을 피하려고 문법을 확장할 수 있도록 한 것이다. 문법 확장에서 오는 다른 의미에서의 가독성 저하는 고려하지 않은 채로 말이다.

그 대가가 문법 확장이라면 난 차라리 코드를 조금 더 중복시키고 더 길게 작성하는 편을 택할 것이다. 수개월, 수년 후에 내가 또 읽을지도 모르는데 그때 메뉴얼도 없는 이상한 언어를 새로 배우고 싶지는 않다.

유명한 해커 Paul Graham이 Arc의 튜토리얼에서 이런 말을 했다.

I wouldn't be surprised if some parts of my code go through 10 or 20 levels of macroexpansion before the compiler sees them, but I don't know, because I've never had to look.

자신이 작성한 매크로 코드를 한 번도 볼 필요가 없었다니. 그것도 타입도 없는 언어에서. 버그가 없었단 말인가, 디버깅을 안했단 말인가. 역시 대단한 해커다. 나도 그 정도라면 Lisp을 안 쓸 이유가 없다. (아니 사실은 있다.) 그치만 난 내가 쓴 쓰레기같은 코드를 보고 고치고 보고 고치고, 울면서 반복한다.

2017-02-23 씀.