프로그래밍 언어 개발에 관심 있는 사람들의 모임입니다.
|
2008-04-03 17:16:00
|
이셋을 어떻게 정의내리고 용어간에 구분을 해야 한다면 그 기준을 어떻게 해야할까요? 그냥 막연한 개념밖엔 갖고있지 않은 우민이라 질문을 올립니다. The future is here. It's just not widely distributed yet. |
트랙백 주소: http://langdev.net/post/trackback/38
익명 함수와 람다 함수의 차이는 저도 모르겠고. (있나요?)
저는 클로져를 말 그대로 lexical closure로 봅니다. 함수가 생성된 시점의 컨텍스트 데이터를 함께 지니고 다니는 거요. 근데 클로져가 그냥 이것 아닌가요?; 더 심오한 게 있는 건가…
익명 함수라는 말 자체가 좀 이상하다는 생각도 듭니다. 익명 정수, 익명 문자열 같은 것은 없잖아요. 함수 객체나 함수자 정도가 적절한 말 같습니다. 익명 함수라는 용어는 PHP 같은 언어에나 어울리겠네요.
아겔님이 떡밥을 던졌다는 것을 알면서도 순순히 낚였다고 생각합니다.마는 어쨌든.
람다함수는 lambda calculus (이거 우리말로 뭐라고 해야되나요?)에서 온게 분명한데, 익명함수는 잘 모르겠군요.
클로져에 대해서 애매한 지식만 가진 저는 저는 일단 구글신의 신탁을 받았는데,
마틴 파울러의 클로져, 그리고 번역을 찾았습니다. (찾은 순서는 반대지만요)
함수를 호출 할 때 인자로 넘기는 코드 덩어리라는군요. 루비의 관점에서 본다면 상당히 그럴듯 합니다. 하지만 저 설명은 코드 덩어리라는데 초점을 줘서 클로져가 가지는 의미랑은 좀 다르지 않나 싶어요. 그래도 또 찾아봤는데,
위키피디아:클로져에 좀 더 마음에 드는 설명이 있군요.
클로져란 하나 이상의 엮인(bound) 변수가 있는 환경(?)에서 실행(평가?)되는 함수라는군요.
쓰고나니 홍민희님의 설명이랑 같은거네요. 클로져란 개념이 스킴에서 나왔다니, 스킴 관련 페이퍼를 읽어보면 정확한 정의를 알 수 있을것 같지만 게을러서 미룹니다.
클로저는 생성 당시의 상태를 저장하고 있는 객체입니다.
위의 코드에서 n이 바인딩되어 람다함수에서 사용합니다. 즉, 람다함수가 생성될 때 n의 상태가 저장되는거죠. 그리고 보통 대부분의 언어에서 람다함수가 이름이 붙어 있지않기 때문에 익명함수라고도 부릅니다.
클로져가 객체라면 객체가 아닌 언어에서는 좀 애매해질 수도 있지 않을까요? 쓸데없는걸로 딴지거는 것 같지만 최대한 formal한 정의를 찾아보자는거죠.
함수를 일급객체로 다룰수없다면 클로저도 나올수 없겠죠..
‘일급’ 객체는 무슨 뜻인가요?
first-class function을 말하는 것 같습니다.
음 그렇다면
이 코드에서 funcb가 클로져가 되는 셈인데,
일급객체란
C에선 execution중에 함수가 생성되지는 않잖아요. 물론 저 중첩 함수 정의는 C표준은 아니고 GCC에서 따로 지원하지만요.
C에서 저런 클로져가 가능한가요?
일단 C표준에선 중첩함수를 허용하지 않아요. 그리고 함수를 리턴할 수도 없어요.
예. 그래서 GCC 한정이라는거죠.
흔히 PL에서 말하는 first-class object는 그 obejct를 다룸에 있어 언어상에 제약이 없는 object를 말합니다. C언어에선 정수는 인자로 넘길수도 있고 리턴할수도 있고, 사칙연산에 제한이 없으므로 일급객체라고 할수 있습니다. 반면에 함수는 인자로 넘겨받거나 리턴할려면 함수 포인터를 써야되는등의 제약조건이 있죠. 이건 일급객체가 아닙니다.
C++의 Boost.Lambda 같은 것을 보면 그렇지도 않은 것 같습니다.
사실 그 자체로 어떤 연산의 대상이 될 수 있다면 일급이라고 볼 수 있겠죠. (함수라면 부분적용이나 합성 같은)
엄밀하게 말해서 c/c++은 기본적으로 함수가 아닌 함수’포인터’에 대한 연산을 제공하는것이고, 이들을 이용하여 클래스로 잘 포장한것이니 이를 ”언어레벨에서” 다른 값들과 같은식으로 처리를 지원한다고 말하긴 어렵겠지요.
물론 boost.lambda은 훌륭합니다. ;-)
‘객체’라는 표현이 ‘객체지향’의 객체의 고유명사는 아니겠지요.
클래스 정의를 하고 인스턴스를 만들고, 상속을 하지 않더라도 객체라는 말은 틀린 정의는 아닌것 같습니다.
음 그렇군요 너무 좁은 의미로 생각한 것 같네요.
대략 정리해보면 클로져에 대해서만 바인딩에 대해서 연관이 있는 녀석이고, 나머지들은 알고 있는 것들과 같은것이었네요. ㄳ^^
어힉쿠나 만선이로구나!!!
…라고 생각하면 나쁜가요?;;;
아싸 조쿠나 =3
슬슬 정리해서 클로져라는 말에 들어있는 의미가 정확히 뭔지 알아보고 싶어요.
저는 2번이라고 생각하는데, 왠지 4번이 맞을 것 같기도 하군요.
“정의상으로는 2번이 맞지만 가장 널리 알려진 구현 방식은 4번이다” 정도가 정답에 가깝지 않을까요?
4번은 2번의 부분집합이니까요. 객체로 다룰 수 없는 중첩함수를 closure라고 볼 수 있는건지 아닌지가 달라질 것 같아요.
클로져의 용도를 생각하면 크게 고민할 부분이 아닌 것 같습니다. 클로져로 된 함수를 다른 문맥에서 호출할 수 있어야, “생성된 시점의 문맥”을 기억할 필요가 생기겠죠.
결국 함수를 전달 가능하거나, 혹은 함수 포인터—PHP 같은 경우 어이없게도 함수 이름 문자열을 반환하는 식입니다—라도 있어야 클로져라고 할 수 있을 것 같습니다. 전 위에서 2번의 코드 블럭을 그런 의미로 생각했거든요.
그리고 또 드는 생각이, 실행 시간에 함수를 생성 가능해야겠다—였는데 더 생각해보니 그럴 필요는 없을 것 같고, 내부적으로는 하나의 함수가 컴파일 시간에 만들어진 상태에서, 실행 시간에는 정적인 함수에 대해 문맥 데이터를 커링(currying)해주는 식으로 구현하면 될 것 같습니다. (C++의 인스턴스 메서드에서
this포인터가 사실 첫번째 인수인 것처럼요.)그렇네요. 전달 가능하지 않으면 의미가 없군요.
사실 루비택 번역할 때도 클로져가 뭔지 이해를 못해서 다른 번역자분들께 계속 물어봤고 애매하게 이해했는데 이젠 확실하게 다가오네요.
오랜만에 이 글을 다시 읽어봤는데, 잘못 쓴 부분이 있었네요. 커링이 아니라 부분 적용(partial application)이겠죠?
안녕하세요- 뒷북인지 모르겠으나 방문해서 처음 읽는 글이라 가입인사 겸 몇 마디 적어봅니다. :)
일단 이광근 교수님의 KAIST CS320 (2001~2003)[1] 또는 서울대 4190.219 [2] 강의 슬라이드가 개념탑재에 유익하겠다는 생각이 듭니다. Scope 쪽에서 “환경(Environment)”과 “메모리(Memory 또는 Store)”, 그리고 “람다셈법(Lambda Calculus)”에 관해서 말이죠.
[1] http://ropas.snu.ac.kr/~kwang/320/02/#progress [2] http://ropas.snu.ac.kr/~kwang/4190.310/07/#progress
익명함수, 람다함수, 클로져는 대략 같은 개념에 대한 여러 이름들이라고 생각할 수 있습니다.
람다셈법은 “함수”들을 값으로 다루는 함수형 프로그래밍 언어들의 근간입니다.
e ::= x | λx.e | e e
람다셈법에서는 이름을 가진 함수를 만들기 위해서 반드시 이름 없는 함수, 즉 “익명함수”를 만들고 거기에 이름을 붙여줘야만 합니다. 사실 이름 없는 함수를 억지로 만드는 것이 아니라, “함수 값”을 만들고 여느 값과 마찬가지로 이름을 붙이는 것이죠. 이렇게 “익명함수”를 만드는 문법으로 “λ”를 사용하였기 때문에 “람다함수”라고도 부르는 것입니다.
클로져(Closure)는 어설픈 익명함수와 구분짓기 위해서 등장한 용어로 이해하면 좋습니다. 많은 사람들이 C와 같은 언어에서 함수(펑션, function)라고 부르는 존재는 엄격하게는 함수가 아닙니다. 그냥 독립적인 이름공간을 갖는 코드 덩어리가 함수와 유사하게 쓰일 수도 있기 때문에 “함수”란 이름이 남용 당한 것이죠. 사실 C에서도 함수포인터가 있기 때문에 함수를 값과 비스무레하게 다루는 척 할 수 있습니다. 그러나 클로져라고 부르는 진짜 함수 값과 C의 함수포인터가 갖는 가장 큰 차이점은, 전자는 이름공간이 매 함수 값마다 독립적이지만, 후자는 하나로 고정이 되어 있다는 것입니다. 이름공간은 앞서 CS320 자료의 “환경”에 해당하는 것으로, 이름들이 실제로 가리키는 메모리 상의 주소를 관리하는 역할을 하는데, 이것을 따로따로 여럿 만들 수 있느냐 아니면 하나로 고정되어 있느냐의 차이인 것이죠.
GCC가 중첩된(nested) 함수 정의를 문법으로 지원하더라도 정의 당시 부모함수의 지역변수 이름들이 의미하는 메모리 주소까지 몽땅 다 포착(close)하여 중첩된 함수에게 매달아 줄 수 없다면 진정한 의미의 “클로져” 또는 “익명함수”, “함수 값”을 지원해주는 것은 아닙니다. C는 지역변수와 스택이 대응되는 것이 언어의 중요한 “기능”이기 때문에 근본적으로 클로져 지원이 불가능합니다. 함수는 실행이 끝나면서 자기 지역변수들을 올려두었던 스택에 대한 권한을 잃어버립니다. 그런데 자기가 생성한 클로져를 되돌려주어 밖에서 자유롭게 쓰는 것이 가능해진다면 클로져가 쥐고 있는 스택 상의 지역변수들 주소 때문에 스택을 함부로 건드릴 수 없게 됩니다. 스택이 더 이상 스택이 아닌 것이죠. 클로져를 지원하게 하려면 C언어의 기초부터 다시 설계해야 합니다.
이렇듯, “클로져”는 어설픈 익명함수가 아니고 정의 당시 이름들의 의미를 잡아서(close) 만든 진짜 함수임을 강조하기 위한 용어라고 생각할 수 있습니다. 클로져는 암묵적으로 정적 유효범위(static scoping)를 가정하는 것이라고도 할 수 있겠군요.
순수한 (함수형) 프로그래밍 언어에서는 함수 값/익명함수/클로져의 정의가 명확합니다. 그러나 암묵적인 상태변화(side-effect)를 허용하는 불순한 프로그래밍 언어나, 환경과 메모리가 나뉘는 일반적인 명령형/기계중심적 프로그래밍 언어에서는 클로져의 개념이 정의나 구현 깊이에 따라 미묘하게 다를 수 있습니다.
저는, 불순하고 기계중심적인 보통 언어들에서 어설프게 함수를 값으로 다룰 수 있게 하는 일은 불필요한 복잡도만 높이는 나쁜 일이라고 생각합니다. 타입시스템과 같은 최소한의 안전장치도 없는 상태에서 함수 값이라는 강력한 힘을 함부로 쓰기 시작한다면 어느 누구도 감당할 수 없는 사태가 발생하기 때문이죠. 함부로 휘두르기 위한 무언가라면 또 모를까.. :)
-재호
명확한 설명 좋습니다.
다만 “불순하고 기계중심적인 보통 언어들에서 어설프게 함수를 값으로 다룰 수 있게 하는 일은 불필요한 복잡도만 높이는 나쁜 일이라고 생각합니다.” 하신 부분은 제 생각과 다릅니다. 패러다임은 그저 패러다임일 뿐입니다. 어떤 일에는 어떤 패러다임이 더 알맞을 수는 있지만, 그렇지 않다고 언제나 나쁜 것은 아닙니다. 칼을 쥐고 있다고 누구나 함부로 휘두르지는 않습니다. 제 생각이지만 netj님께서 C를 쓸 일이 생긴다 하더라도 함수값을 함부로 다룰거란 생각은 들지 않는군요.
어떤 패러다임이나 언어를 좋아하는 것은 누구나 할 수 있는 일이지만, 섵부른 평가는 스스로에게나 다른 분에게나 그리 좋지 않다고 생각합니다.
누군가에게 오해와 편견을 심어줄지도 모른다는점에서 조심하자는 말씀이 참 맞습니다만, netj님도 ‘살인범은 나쁘다 좋다’의 문맥에서 말씀하셨다기보다 ‘바람직하지 못한 설계’라는 문맥에서 말씀하시고, pure functional의 입장에서 말씀하시다보니 그렇게 말씀하신것 같네요.
이럴 줄 알고 조심스레 “저는,”으로 문장을 시작했던 것인데… ^^
저도 C 프로그래머이자 Java 프로그래머입니다. 일상생활에선 거의 shell script로 기계와 이야기하며 살아갑니다. 제 글만 놓고 보면 Haskell 같은 순수 함수형 언어를 신봉하는 성직자처럼 보일 수 있다는 것 잘 압니다. ^^ 순수한 언어에서 여러 문제의 답을 찾아왔던 것은 사실입니다. 그러나 성직자이기에 앞서, 저도 그런 엄격한 환경보다는 하고 싶은 일을 내키는대로 표현할 수 있는 자유로움과 느슨함이 더 편안한 보통 사람입니다.
제가 경험했던 분명한 사실 한 가지는, 순수 함수형 언어들로 타입과 화살표로 잘 프로그래밍할 수만 있으면, 어려운 문제를 제대로 풀는 일이 많이 쉬워진다는 것입니다. 여기에는 함수를 값으로 다룰 수 있는 강력한 표현력이 큰 이유로 작용하겠지만, 그런 큰 힘을 통제할 수 있는 여러 안전장치들의 도움이 함께 하기에 가능한 일이라고 봅니다. 이러한 안전장치를 채우기가 어렵거나 불가능한 곳에서 너무 강력한 힘을 허용하다보면, 오히려 감당할 수 없는 괴물을 만들기만 쉬워지기 때문에 제가 두려워하는 것입니다. 가령, 아직 핵융합 기술이 불완전하다고 말하는 이유는, 핵융합 반응을 시작할 기술을 찾지 못해서라기보다 이런 무시무시한 힘을 통제할 현실적인 기술이 부족해서인 것 처럼요. 중국산 불량 토카막에서 핵융합을 시작했다가는 지구를 다 녹여버릴 지도 모를 일이죠. -_-
저는 C 프로그램을 짤 때 매크로를 상당히 많이 씁니다. (말과 행동이 약간 다르죠 ㅠ) 매크로가 (함수 값 못지 않게) 강력하면서 위험하다는 것은 누구나 잘 아실 겁니다. 그러나 잉크도 절약할 수 있고(물론 타이핑..) 고차(higher-order) 함수를 흉내낼 수 있어서 꿩대신 닭으로 애용합니다. C 프로그램의 크기를 언제나 감당할 수 있는 수준으로 유지하고 스스로 통제가 가능한 수준에서만 매크로를 사용하려고 노력하기 때문에 다행히 저는 매크로에게 크게 혼난 일이 없습니다. 그러나 제대로 통제받지 않는 C 프로그램이 팽창하면서, 위험천만 매크로까지 범벅이 되어 고통받는 사람들을 주위에서 많이 보았습니다. 매크로 확장을 디버깅할 수 있는 C 전처리기는 들어보지 못했습니다. 매크로를 만들어 쓰는 사람이 모든 책임을 지고 가야하는 것이죠. ㅠ 이 쪽을 바로잡아보려는 Staged Computation[1]이라는 분야도 있긴 하지만 “병 주고 약 짓는” 느낌이 강합니다. 핵심원인은 사실 “감당할 수 없는 크기”가 된 것인데 말이죠. 자기가 짠 코드에 스스로 당하며 끼니를 이어가는 사람들이 대부분인 곳이 IT입니다. 지금도 그러한데 더 무시무시한 짓들도 할 수 있게 만들면 사람들의 행복에는 별로 도움이 되지 않을 것 같다는 것이 제 생각입니다. ㅠ
아무튼, 얘기가 또 길어졌는데요, 제가 특정 패러다임/언어를 배척하거나 옹호하는게 아니고, 누구도 감당할 수 없는 힘을 아무나 마구 쓸 수 있게 해주는게 두려운 것으로 이해해주시면 감사하겠습니다. 사실 요즘엔 이에 대한 좀 더 근본적인 답을 프로그래밍 언어가 아닌 다른 곳[2]에서 찾고 있답니다. :)
-재호
[1] http://portal.acm.org/citation.cfm?id=1111320.1111060
[2] http://catb.org/~esr/writings/taoup/
오오… 답글 달려고 로긴했는데 바로 notify해주네요. 멋진 기능 만들어주신 민희흉 멋쟁이!
netj님의 말씀에 공감하는 부분도 있지만, 그렇지 않은 부분도 있어 조금 중얼거려야겠다고 생각했습니다.
차별도 싫지만, 역차별도 만만찮게 아름다운 꼴은 아닌거 같아요. netj님도 조심스럽게 말씀해주셨고, semmal님도 게시글의 중심을 잡기 위해 용감하게 지적해주셨다고 생각합니다. 굳이 얼마 되지도 않는 인원들끼리 편가르기가 되지않고 서로의 지식을 자랑하는 교만한 자리가 아니라, 서로의 의견을 나누며 지혜를 모을 수 있는 장이 되기를 바랍니다.(아, 저만 혼자 오바해서 생각하는거겠죠?)
그런거야 어찌되었든 여기 계신 어느분도 공감해주시지 않을지도 모르겠고, 바보취급하실 가능성도 큽니다만 낚시적 썰을 풀어볼랍니다.
제 생각도 ‘규모의 감당’으로서 일차적인 언어적인 문제만이 아니라는 점에서 공감합니다. 그리고 제가 그간 느끼고 생각해오던 바로는 흔히 말하는 패턴(디자인패턴이든 엔터프라이즈패턴이든간에), 아키텍쳐, 혹은 개발방법론이나 PM이론등이 이런것들에 대한 처방이라고 나오던 것들이 아닐까 싶습니다.(TAOUP을 예로 들어주신것처럼 말이죠.)
(논쟁의 여지보다 감정적 여지가 더 많겠지만)그런면에서 자바의 탁월한점(모두들 비난해 마지않는, 혹은 지적하는 저로서도 25%의 비아냥일지도)은 그 유연성 없음이 아닐까 싶습니다. 초기부터 단순하게 문제를 해결할 길을 열어둘수도 있었음에도 계속해서 그러한 언어 디자인을 고수해 가는데에는 단순히 JSR을 검토하고 정식릴리즈에 반영하는 프로세스가 완고하고 관료주의적이기만한 문제는 아니라고 생각합니다. 언제나, 어떠한 문제든 ‘정식절차’를 거쳐서 처리하도록 유도하는 방식이라고 생각합니다. 초기에 어떤 무언가를 프로토타이핑하려하거나 신기하게 반짝거리는 뭔가를 만드는데에는 도움이 안되고, 개발자의 알량한 지식과 테크닉을 자랑하는데에도 별 도움이 안되는 언어지만, 반대로 대부분의 개발자들이 평준화된 코드를 ‘생산’하도록 유도하고 코드블럭들을 통합하여 거대한 무언가로 만들어 내는데 어느정도 기여를 하지 않았나 생각합니다.
물론, 예술가적인 관점의 개발자라면 지금까지의 내용들에 동의하시기 힘드리라 생각합니다. 또는 실용주의, 혹은 사실은 편의주의적인 관점에서 자바는 감당하기 힘든 부분이겠지요.
그리고 그런 ‘대안의 문제’로서(비록 능력부재+귀차니즘으로 문맥간 비약이 크지만) 말씀드리고 싶은 부분은 오히려 그런 견고하고, 역으로 말하면 ‘경직된’ 개발에 대한 시각을 강요하는것들(디자인패턴, 엔터프라이즈패턴, 개발방법론, …특히 자바와 엔터프라이즈개발, 아키텍쳐 분야에서는 강요 아닌 강요인 ‘교조적인’ 책들이 참 많죠.)이 가끔은 개발자의 생산성이나 창의성을 갉아 먹는것은 아닐까 싶습니다.
먼 예를 들지 않아도, 자바에서 텍스트 파일을 읽어 그 내용을 표준출력으로 뿌리는것과 파이썬이나 루비에서의 같은 코드는 희극적으로 그 차이가 확연(http://www.trepca.si/blog/?p=12)하죠. 또는 그런 정규화된 방법을 통해 정식적인 경로로서의 명시적인것들만을 중시하다보니 SpringFramework와 같은 XML-Hell도 심심찮게 볼수있겠죠.
‘정규화된 지혜’가 필요할지도 모르겠지만, 언제나 그 끝이 해피엔딩은 아닌것 같습니다. 방금 말씀드렸던 그러한 부분들은 적어도 제가 생각하기에는 지식이나 테크니컬한 해법만이 아니라 ‘지혜로운’ 방법을 추구하기 위해, 그리고 결국에는 그것에 너무 고취한 나머지 교조적으로 경직되버린 예였습니다.
그냥 netj님의 본문에도 그런 생각이 뭍어 나고, 이 글타래들의 우려스러운 점도 그런데, “dogmatic X, humble O”…
에코의 ‘장미의 이름’에서였던가요… 신을 섬기기보다는 규율과 관습을 섬기던 그 교회가 그런것들을 지키기위한 잘못된 노력으로 피로 물들고 무너져 내렸을때 그렇게 말했던것 같습니다.
“지난날의 장미는 이제 그 이름 뿐, 우리에게 남은 것은 그 덧없는 이름뿐..”
전 그러한 ‘방법론’들이 지혜를 찾아, 지혜를 모으고 전수하여 문제들을 해결하고 문제를 예방하는 길이 되어, 허울뿐인 목적을 상실하고 수단이 목적이 되어버리는 우스꽝스러운것이 아니길 바랍니다.
혹여 마음에 안드시는 글이었다면 멍멍이가 짖었다고 생각하시고 추억의 저편으로 철이와 함께 안드로메다로 날려주시길. ^^;
사실 저 같은 경우에도 C나 Java로 짜기전에 주석을 오히려 Haskell로 붙이는 경향이 있습니다. 설계는 Haskell로 짜놓고 그 구현을 다른 언어로 마무리 하는 것이죠. 하지만 언어적인 한계가 있기때문에 모든 것을 그리할 수도 없을 뿐더러, 근본적인 차이때문에 그렇게 해서도 안되는 경우도 생깁니다.
Haskell이 아무리 좋다고 한들, 속도를 요하는 곳에서 C만 못하고, 어플리케이션을 빨리빨리 찍어내는데 Java보다 못합니다. tail-recursion이 아무리 아름답고 쉬워도, while문에 눈이 돌아갈듯이 지저분한 코드를 쓴 것 보다 못할 때가 있는 법입니다. Java 프레임웍이 고수들에게는 “제약” 그 이상의 의미는 없겠지만, 겨우 6개월 학원강의를 마치고 회사에 들어온 신입사원에게도 곧바로 업무를 던져줄 수 있는 유용한 도구입니다.
세상에 존재하는 도구에는 덜떨어진 도구, 우월한 도구 따위는 없다는 게 제 생각입니다. 쓸모있는 도구이기에 존재하는 것이지요. 제가 굳이 몇 마디하는 것은, “무시무시한”이라고 할 만큼 그렇게 무시무시하지 않기 때문입니다. 물론 조금쯤은 위험할 수도 있는 도구이지만, 잘쓰면 그만큼 유용한 것이 없습니다. 그 무시무시한 도구로 짜여진 프로그램을 netj님은 지금 쓰고 계시지 않습니까?
사람들이 대부분 알고있는 것과 다르게 도가에는 “출세를 해라”와 비슷한 말이 있습니다. 그렇다고 이것이 유가에서 말하는 말과 같은 의미는 아닙니다. 유가의 목표가 이름을 알리는 것이 목적이라면, 도가의 목표는 오래사는 것이기 때문입니다. 아무래도 힘없는 백성보다는 높은 관리가 오래사는데 도움이 되니까요. 같은 말도 그 뜻을 해아리면 달라보이는 법입니다.
제 걱정은 우매한 대중들에게 강력한 힘을 안전장치 없이 줘도 괜찮겠느냐는 것입니다. 함수를 이리저리 주고 받으면서 돌아가는 코드가 쓰이기 시작하면 현존하는 정적 프로그램 분석기들은 대부분 무용지물이 됩니다. 단순한 C 프로그램 조차도 배열이나 포인터로 만들어지는 메모리 구조를 요약하는 기술이 걸음마 단계이고, C++ 프로그램은 virtual 함수나 다중상속 때문에 호출관계 분석만 하려해도 모든 클래스 계층을 다 펼쳐놓고 힘들어 해야 합니다. 이러한 상황에서 무슨 짓을 할 지 모르는 임의의 함수를 (심지어 아직 모르는 녀석까지) 허용한다면, 그냥 짠 사람이 제대로 만들었기만을 믿는 수 밖엔 없습니다. 그런 면에서 Java가 심할 정도로 절제된 형태로 진화하고 있는 것은 참 다행입니다. (7에서 closure가 어찌될 지 살짝 걱정이 되긴 하지만)
“무슨 짓을 하고 있는지 아는,” 소양을 갖춘 사람들에게 더 강력한 힘은 언제나 유익하다고 생각합니다. 훌륭한 사람들도 아주 가끔씩은 자기 무덤을 파기도 하니까 안전장치 역시 언제나 유익하다고 생각합니다. 다만, 목적에 따라 안전장치가 힘을 제약할 지, 안전을 희생하고 강한 힘을 허용할 지를 택해야겠죠. 세상의 많은 도구들은 semmal님 말씀대로 다 쓸모가 있다고 생각합니다. 이런 다양성을 구성하는 한 요소로 자유(힘)와 안전의 스펙트럼도 있는 것 같군요. 물론, 제가 쓰는 많은 프로그램들은 안전장치 없는 언어나 도구들로 만들어졌습니다. 그러나 훌륭한 사람들이 만든 프로그램들이기에 (그렇지 않은 도구들은 안씁니다 :) 그들이 안전장치 역할을 했다고 생각합니다.
사람에게 많은 책임을 지우면 불확실하고 서로 피곤해지기도 하니까 기계나 체계가 이를 대신하는게 바람직하다고 생각하는 편입니다. 근데 요즘 들어, 기계가 요상하게 검증할 필요도 없이, 누구나 훑어보면 문제 없는게 뻔하도록 프로그램을 만드는 것이 제일 좋은게 아닌가 하는 생각도 듭니다. 커져가는 프로그램을 작은 조각들로 쪼개어 한 프로그램의 크기를 적절한 수준으로 유지하는 쉬운 방법이 일단 필요하겠고요. (유닉스 정도면 훌륭한 것 같습니다.) 그리고 무엇보다도 사람들이 이를 익혀 꾸준히 실천할 수 있도록 하는 “교육”과 “문화”가 가장 중요한 것 같습니다. 언어도 도구도, 결국 사람이 쓰는 거니까 당연한가요.. ㅎ
-재호
간단한 쉘 프로그래밍을 해야하는데 굳이 타입을 생각하고 추상을 생각하고 안전하게 짜야할까요? 스프레드시트에서 계산을 하기 위해서 그렇게 깊은 수준의 프로그래밍 공부를 해야할까요? 다시는 쓸 일 없을 것 같은 스크립트를 만드는데 생각보다 많은 시간을 투자해야할 이유가 있을까요?
하시는 말씀은 백번 공감하지면 그 말이 적용되는 경우는 잘 따져봐야 한다고 생각합니다.
대부분의 사람들에게 프로그래밍은 그저 무엇을 하는 도구일 뿐이지, 극단적인 컴퓨터 전공자들 처럼 “의미”가 있는 수준이 될 수는 없습니다.
다시 옛날 이야기를 끼워넣겠습니다. “예의”는 유가에서는 좋은 미덕이지만, 도가에서는 나도 귀찮고 남도 귀찮게 만드는 “허례”일 뿐입니다. “지식”은 유가에서는 어려움을 극복할 수 있는 중요한 도구이지만, 도가에서는 어려움이 없는 시기에 남을 깔보는 도구라고 정의합니다. 아무 어려움이 없는데 예의가 무엇이고 지식이 무엇입니까? 정말 알아야 할까요?
netj님은 옳습니다. 하지만, 그렇다고 다른 사람이 틀린 것이 아니라는 말을 저는 계속 하고 싶은겁니다.
흠.. 루비 공부하다가 클로져에 대해 좀 더 명확히 하려고 구글신과 접신하던 중 들어왔습니다만… (저도 만선의 한축을 담당하는건가요?)
솔직하게 말씀드리면 netj 님이 걱정하시는거랑 그 걱정이 실제 소프트웨어 개발에 어떤 영향을 미치는 지 잘모르겠습니다. 뭐 전 저런 전문지식을 가진것도 아니고 평소에 심도 깊은 생각을 하는 것도 아니지만, 언어가 강력하건 아니건 어떤 기능을 훌륭하게 지원하던 어설프게 지원하던, 정적이던 아니던 커다란 - 엔터프라이즈급이라고 하죠. 제가 지난 5년간 일했던 분야가 그거니깐 - 소프트웨어가 ** 사용자가 원하는 대로 작동 ** 하게 하는 것과는 별 상관이 없거 않을까 합니다.
더군다나.. (음. 말꼬리 잡아서 죄송합니다.) 언어의 강력함과 우아함을 떠나서 여럿히 함께 하나의 소프트웨어를 만들때는 다른 사람이 잘 만들었다라고 기대하고 진행하는 것 아니었나요? 그게 틀렸다라면 제가 만약 우습게 closure 를 지원하는 어떤 언어를 쓰는 프로젝트에 들어갔다라면 프로젝트 구성원이 어떻게 되었던 30명이면 30명 전부의 코드를 확인해야 하겠죠. ^^
사실 어떤 좋은 언어를 쓰더라도 막말로 사용자에게 개떡같은 소프트웨어를 만들 소지는 충분히 있는거고, 별 거지 발싸게 같은 언어를 쓰더라도 사용자들이 “따봉”을 외치며 막 춤추고 모자를 하늘로 던지면서 즐겁게 사용할 수 있는 소프트웨어를 만들 여지도 충분히 있는 것 아니겠습니까? ㅎㅎ
ps. 처음 글 쓸때부터 횡설수설이 될거라 예상은 했지만 실제로 그렇게 결론이 나니 좀 그렇네요. ㅠㅠ
재미있는 글이 많네요… 크루져에 관한 거라면 저는 VCL 흠 그러니까 볼랜드사의 C++ 제품을 쓰면서 첨 접해 봤는데요… boost의 람다로도 비슷하게 구현이 가능하다고는 들었는데 뭐 이건 편하고 깔끔하게 쓰려면 언어적으로 지원을 해줘야 하는거 같아요.. BCB 같은 경우에는 언어적으로 크루져를 지원해 주는데 64바이트의 일종의 전용 포인터를 사용해요 상위 는 클래스 포인터 하위는 펑션 포인터죠.. 오브젝트들이 서로 상관이 없더라도 서로 호출해 줄수있어서 매우 편리 하더라고요…. 제가 알고 있는 지식은 이거정도네요 ㅎㅎ
람다함수는 람다연산의 구현을 함수표현으로 한 것인데, 람다연산은 논리학(언어학)의 술어논리에서 온 것으로 알고 있습니다. 언어학을 독학으로 공부하다가 알게된 것이라 정설은 아닐지도. ^^;
클로저는 코드 덩어리(스트링 블럭) + 환경(메모리 스택) 을 통째로 다룰수 있는 단위가 구현된 것 같습니다. 실제로 코드덩어리와 + 환경은 어디에서나 존재하지만, 그것을 symbol 로 지정할 수 없다면 클로저가 아니겠네요.
익명함수는, 클로저의 구현의 한 형태로서, 함수 정의와 같은 표현을 사용할 때, symbol에 binding 되기전의 코드블럭을 언어차원에서 지칭하려는 표현이겠습니다.
Javascript The Definitive Guide 5/e 한역을 보고 개인적으로 이 지면을 빌어 정리해봤습니다. prototype-based OOPL 관점에서만 보고 이해할 수 있는 수준이겠네요. 부끄럽게도 개념부족한 댓글일지 모르겠습니다만, 이런 공간이 있어서 감사하기도 합니다. 꾸벅~!
참 Javascript 에서 클로저는 private과 같은 class-based OOPL 의 전형적인 특성을 구현하는 하나의 방법으로 최근에 많이 알려지게 된 것이라 주객전도된 경향이 없지않아 있어보일 수 있습니다. ^^;
명쾌하게 다가온 글입니다. 감사 드립니다.