프로그래밍 언어의 발전 방향

게임 코딩 스쿨에서는 “C# 바로 알기”, “JavaScript 바로 알기” 시리즈를 통해서 각 언어를 제대로 사용하는 방법에 대해 설명하고 있습니다. 수많은 언어 중에서 하필 두 언어를 고른 이유는 단순히 두 언어가 게임 프로그래밍에 많이 사용되기 때문만은 아닙니다. 두 언어를 선택한 또 다른 이유는 두 언어가 빠른 속도로 발전하고 있고, 여기서 배울 점이 많이 있기 때문입니다. 재미있는 사실은 서로 전혀 다른 배경과 목적으로 탄생한 두 언어가 놀랍게도 유사한 방향으로 발전하고 있다는 점입니다.

우리가 자주 사용하는 프로그래밍 언어로는 C, C++, Java, C#, Python, Ruby, JavaScript 등이 있습니다. 대부분의 주류 언어는 객체지향 프로그래밍 언어로 분류되고, 문법이나 용법, 표준 라이브러리 등에 차이는 있어도 큰 맥락에 프로그래밍을 하는 방법은 대동소이합니다. 가장 큰 차이라면 C#, Java와 같이 정적 타이핑을 하느냐, Python, Ruby, JavaScript처럼 동적 타이핑을 하느냐의 차이 정도만 있을 뿐입니다.

그런데 학계에서 프로그래밍 언어를 전공한 사람들은 이런 주류 언어를 연구하지 않습니다. 학계에서는 주로 연구하는 언어는 “함수형 언어”로 분류되는데, 함수형 언어 중에 대중적으로 잘 알려진 언어는 Lisp, Scheme, ML, OCaml, Clojure, F#, Scala, Haskell이 있습니다. 대중적으로 잘 알려지지 않았지만 학계에서 많이 사용하는 언어로는 Coq, Idris, Agda 같은 다소 특이한 언어들도 있습니다. 물론 이외에도 수많은 연구용 언어들이 존재합니다.

주류 언어와 함수 언어는 오랜 시간 공존하며 직간접적으로 많은 영향을 미쳐왔습니다. 일례로, Java가 나오면서 대중화된 가비지 콜렉션(garbage collection)은 함수 언어에서는 이미 Lisp 시절부터 존재한 오래된 기술입니다. 함수 언어는 주류 언어와 달리 immutable 타입을 강조하고, 기존 메모리를 갱신하는 대신 새로운 값을 만들어내는 방식으로 계산을 수행하므로, 일일이 메모리를 수동으로 할당하고 해제하는 것이 불가능했습니다. 이런 언어 특징 때문에 일찌감치 자동 메모리 관리 기술이 발달할 수밖에 없었습니다.

반대로, 메모리를 한 번 할당한 다음 할당된 메모리를 갱신하는 방법으로 계산을 수행하고, 성능을 강조했던 주류 언어는 상대적으로 가비지 콜렉션의 도입이 늦을 수밖에 없었습니다. 초기 절차형 언어 Fortran, Algol, C에서는 메모리 관리를 수동으로 하는 것이 크게 문제가 되지 않았으나, 점차 복잡해지는 소프트웨어를 작성하기 위한 객체지향 프로그래밍이 나오면서 수동 메모리 관리는 점점 부담이 됩니다. 다행히 해결책은 이미 함수 언어에서 수십 년 전에 고민한 가비지 콜렉션에 있었고, Java 이후 현재의 주류 프로그래밍 언어는 대부분 가비지 콜렉션을 채택하고 있습니다.

함수 언어가 주류 언어에 영향은 미친 또 다른 사례로는 Java와 C#에서 Generic으로 알려진 Parametric Polymorphism이 있습니다. 한국말로 다형성으로 번역하는 Polymorphism에는 Subtype Polymorphism, Parametric Polymorphism, Ad-hoc Polymorphism 등 여러 방식이 존재하는데, Java 5, C# 2 이전전의 객체지향 프로그래밍 언어는 Polymorphism이 곧 Subtype Polymorphism인 것처럼 용어를 사용했습니다.

Java 5 이전 버전의 Java를 사용해 보신 분들은 아시겠지만, Generic이 없으면 인자 타입만 다른 똑같은 함수를 여러 개 정의하거나, java.util.Arrayssort 메소드처럼 타입 정보 없이 가장 범용적인 타입인 Object[]를 처리하는 메소드를 작성하는 수밖에 없었습니다. 당씨 선과 마이크로소프트는 이런 불편함을 해결하기 위한 방법을 찾기 시작했고, 역시나 해결책은 이미 함수 언어에서 수십 년 전에 개발한 Parametric Polymorphism에 있었습니다.

이후에도 주류 언어는 끊임 없이 함수 언어의 개념들을 빌려오기 시작합니다. C#과 Java의 람다(lamba)가 또 다른 대표적인 예제입니다. 함수 언어의 가장 큰 특징은 함수가 first-order라는 점인데, 쉽게 말해 함수를 다른 타입과 마찬가지로 함수의 인자로 넘기거나 리턴 값으로 받을 수 있고, 변수에 저장할 수 있는 특징을 말합니다. JavaScript가 수많은 결점들에도 불구하고, 지금까지 살아남고 발전하고 있는 가장 큰 이유도 함수가 first-order라는 점을 꼽을 수 있습니다. 왜냐하면 first-class 함수로 할 수 있는 일이 상상을 초월할 정도로 많기 때문입니다.

서두에 JavaScript와 C#은 서로 전혀 다른 배경에서 탄생하고 발전하는 언어임에도 불구하고 발전 방향이 놀랍게도 유사하다고 말씀드렸습니다. 그 이유는 간단합니다. 두 언어 모두 함수 언어의 개념들을 차용해 오고 있기 때문입니다.

앞으로 주류 언어가 어떤 방향으로 발전할지 예측하는 일도 어렵지 않습니다. 함수 언어가 이룩한 성과 중에서도 아직 주류 언어가 가져오지 않은 게 무엇인지만 살펴보면 되기 때문입니다. 물론, 이미 지금 프로그래밍 언어 학계가 연구하고 있는 따끈따근한 연구 주제가 아닌 이미 10-20년 이상 시간을 가지고 검증한 기술이어야 합니다. 주류 언어는 수많은 대중을 상대하는 만큼 보수적일 수밖에 없기 때문입니다.

사실 변화는 이미 나타나고 있습니다. C# 3 LINQ, C# 5 async 함수, C# 6 null propagator, ES 7의 async 함수 등의 공통점이 무엇일까요? 정답은 Monad입니다. LINQ, async 함수, null propagator 등은 전혀 다른 기능처럼 보이지만, Monad라는 일종의 수학적인 구조를 따르고 있습니다. LINQ는 List Monad의 다른 이름, async 함수는 Future Monad의 다른 이름, null propagator는 Maybe Monad의 다른 이름일 뿐입니다.

임의의 Monad를 직접 만들어 쓸 수 있는 함수 언어와 달리, 주류 프로그래밍 언어는 이 중에서 유용성이 검증된 일부 Monad를 언어 기능으로 제공하는 단계라고 생각할 수 있습니다. 앞으로 한동안 주류 프로그래밍 언어는 여러 Monad를 가져오는 작업을 할 것으로 보입니다. 이 단계를 지나고 나면, Haskell의 do 표기법이나 F#의 computation expression처럼 언어 사용자가 직접 임의의 Monad를 정의할 수 있는 방법을 제공할 가능성도 있습니다.

저는 지금이 변화의 시기라고 생각합니다. 소프트웨어는 계속 복잡해지고 있고, 과거 절차형 언어에서 객체지향 언어로 넘어간 것과 마찬가지로 지금은 함수 언어가 이런 복잡성을 해결할 수 있는 대안으로 떠오르고 있습니다. Clean Code의 저자이며 객체지향 디자인 패턴과 원리를 강조한 Robert Martin이 지금은 Functional Programming을 전도하는 것을 보며 무엇을 느끼시나요?

One thought on “프로그래밍 언어의 발전 방향

  1. Pingback: 프로그래밍 언어의 발전 방향 | 서광열의 코딩 스쿨

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 )

Twitter picture

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

Facebook photo

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

Connecting to %s