열두 개의 새로운 시스템 언어와, 카터 행정부 시절까지 거슬러 올라가는 하나를 살펴본다.
Toggle navigationColin's Notes
2023년 3월 22일 게시
여기 최근 등장한 시스템 언어들을 빠짐없이 다루지는 않지만 대략적으로 정리해 본다. 이전 글에서 이야기했던 것처럼 안전성과 문법과 관련된 주목할 만한 점들을 적어 보겠다. 대략 실전 준비도와 인기도 순서대로 나열했다. 더 높이 있어야 할 것을 낮게 두었다면 미안하다.
이 목록을 정리하면서 왜 이렇게 많은 언어가 최근에 만들어졌는지 궁금해졌다. 일부는 llvm 같은 도구가 예전의 컴파일러 제작 도구보다 훨씬 강력해졌기 때문일 것이다. 하지만 새 언어의 진입 장벽도 높아졌다. LLVM의 존재 때문일까? 확신은 없다. 이 언어들 중 상당수는 대신 C나 C++ 또는 QBE를 백엔드로 사용한다. 흥미로운 점으로서 각 언어마다 백엔드도 함께 적어 두겠다.
Rust에 대해서는 많이 말할 필요가 없을 것이다. 이 분야의 가장 큰 주자이고, 이 목록에서 1.0 릴리스를 넘긴 유일한 언어다.
참조 카운팅도 아니고 GC도 아닌, 그러니까 일종의 수동 메모리 관리를 유지하면서도 Rust 프로그램을 매우 메모리 안전하고 빠르게 만들 수 있다는 점이 Rust의 가장 큰 명성이다. 하지만 거기에 합 타입과 패턴 매칭 같은 다른 좋은 코드 안전성까지 결합되니 Rust는 더욱 훌륭하다. 안전한 Rust는, 예외적인 상황을 위해 “unsafe”로 표시된 블록을 둘 수는 있지만, 실용적인 안전성을 많이 제공한다. Rust는 코드가 일단 컴파일만 되면 첫 시도에서 크래시 없이 의도한 대로 동작할 가능성이 꽤 높은 그런 언어 중 하나다.
내가 Rust에서 가장 싫어하는 점은 수명이 너무 자주 자동으로 생략되어 보이지 않는다는 사실이다. 그래서 실제로 명시적으로 적어야 할 때는, 그런 일이 너무 드물어 감이 떨어져 있기 때문에 가끔 꽤 고생하게 된다. 그리고 trait의 사용도 내 생각에는 너무 과해질 수 있다.
아, 마지막으로 borrow checker 때문에 가비지 컬렉션 언어에서는 아주 사소한 일부 데이터 구조를 정의하기가 어렵다. 나는 Scheme, Ruby, Java에서 배운 재귀 패턴을 자주 사용하는데, 이것들이 Rust와는 잘 맞지 않는다. 물론 적절한 수명을 쓰면 가능하다. 때로는 이런 그래프 같은 데이터 구조 없이 문제를 해결하도록 코드를 다시 구성하는 편이 더 낫다.
Zig는 아직 1.0 릴리스는 아니지만 0.10.1 버전치고는 상당히 다듬어져 있다. 여기 있는 어떤 언어보다도 정신 면에서는 가장 C에 가까울 수 있고, 어떤 언어보다도 가장 빠른 프로그램을 만들어 내기도 한다. Zig는 아마 Rust 다음으로 가장 인기 있고 성공적인 새로운 시스템 언어일 것이다.
다른 새 언어들처럼 이 언어도 C보다 훨씬 안전하다. 비록 이 목록의 다른 언어들보다 안전성 혁신은 적은 편이지만 말이다. 모든 메모리 할당이 수동이긴 해도, 할당자를 쉽게 바꿀 수 있고 메모리 안전성을 검사하기 위해 디버거 할당자를 선택할 수도 있다. 사실 할당자를 반드시 선택해야 한다는 점 자체가 기능이다. Zig 코드를 읽으면 할당이 일어나는지 아닌지를 쉽게 알 수 있다. 할당하려면 반드시 할당자가 있어야 한다.
Zig는 C와 C++ 도구 체인에 대한 대안을 제공한다는 점에서 매우 인상적이다. 우리 빌드 환경의 몇 가지 아주 제한적인 조건만 아니었다면, 나는 직장에서 현재 진행 중인 대형 C++ 프로젝트의 빌드를 Zig로 다시 구성했을 것이다.
문서는 Rust보다 다소 뒤처져 있지만, 프로젝트가 더 이른 개발 단계에 있으므로 그건 예상할 수 있는 일이다. 홈페이지에는 언어 기능 사용을 보여 주는 좋은 예제 코드 조각이 많고, 언어 레퍼런스도 잘 되어 있다.
Odin은 단순한 문법, 고성능 컴파일, 고성능 실행 파일을 목표로 설계되었다. Pascal, Oberon, 그 밖의 Wirth 계열 언어들의 영향을 받았는데, 이는 좋은 일이다. 나는 Odin의 많은 설계 선택이 정말 마음에 든다. 다른 현대 시스템 언어들에 비하면 안전성 장치가 가장 적을 수도 있지만, 그래도 큰 비용 없이 C++보다 훨씬 나은 안전성을 제공한다.
Odin은 Rust나 Ruby의 “모든 것이 표현식이다” 접근 대신 C, Pascal 등처럼 명령형 문을 사용한다. 그 대신 “or_else” 같은 멋진 연산자를 제공해 조건 표현식을 쓸 수 있게 하면서 잘 보완한다. “if”를 표현식으로 쓰는 데 익숙해지고 나면 다시 돌아가기가 어렵다.
Odin은 실제 고성능 애플리케이션에 사용되고 있다. 외부 라이브러리와의 상호 운용 지원이 많고, 인기 있는 그래픽 및 오디오 라이브러리 바인딩도 갖추고 있다.
게임 개발과 가까운 언어답게 복소수와 쿼터니언이 언어의 내장 타입이라는 점도 어느 정도는 납득이 간다.
Jakt는 Serenity OS 프로젝트의 일부다. Jakt는 Serenity 애플리케이션을 작성하기 위한 언어로 의도되었다. 2022년에 아주 빠르게 만들어졌고 이미 self-hosting 상태다. 하지만 Jakt는 Serenity에서만 쓰이도록 제한되지는 않는다. 현재는 C++를 생성하므로 거의 어디서나 컴파일할 수 있다. 이 언어의 개발 속도는 정말 인상적이다.
흥미롭게도 Jakt의 최상위 목표 중 하나는 가독성이었다. 예를 들어 함수 인자는 대부분의 언어처럼 위치 기반이 아니라 항상 이름이 있다.
설계자들은 프로그래밍 언어가 어떠해야 하는지에 대한 내 생각과 매우 잘 맞는 선택을 많이 했다.
Hare는 아주 새로운 언어로, 첫 오픈소스 릴리스가 2022년에 발표되었다. Hare는 직접적인 C 대체재에 가장 가깝다. 매우 작다. (3.5인치 플로피 디스크에 들어간다.) 컴파일러 백엔드로 QBE를 사용하며, 이것이 일부는 이 언어의 작은 크기를 설명해 준다. QBE는 C로 작성된 최적화 백엔드로 LLVM보다 훨씬 작다.
Hare는 C의 공간적 메모리 안전성을 개선하는 여러 기능을 갖고 있지만 시간적 안전성은 그만큼은 아니다. 다만 로드맵을 보면 borrow-checker를 고려하고 있는 듯하다. 완전한 match와 switch, 강제되는 오류 처리, 그리고 null 값 처리 강제는 전반적으로 C보다 훨씬 버그가 적게 만든다. 문은 표현식이므로 Rust처럼 예를 들어 “if” 표현식 문장의 결과로 변수를 초기화할 수 있다.
Hare 개발자들은 자유로운 플랫폼만 지원할 계획이므로 Mac OS나 Windows는 영원히 지원하지 않을 것이다.
Hare 홈페이지에는 Hare의 안전 기능만을 다루는 문서가 있다.
Vale는 “빠르고, 안전하고, 쉬운” 것을 목표로 한다. Vale는 메모리를 관리하기 위해 세대 참조라는 새로운 기법을 사용한다. 일종의 참조 카운팅 기법이지만 소유권 분석을 결합해 실제 참조 카운트와 free / allocation을 최소화할 수 있게 한다. 이들은 Vale가 네이티브 컴파일 언어 중 “가장 안전하다”고 주장한다. 언어를 더 빠르고 더 안전하게 만들기 위한 Region Borrow Checker도 개발 중이다.
이 언어는 이미 매우 유망해 보인다. 여기 적은 것 외에도 많은 기능이 더 있지만, 아직은 포부 단계인 것도 많다. 현재 언어는 초기 알파 단계다. 메모리 관리와 단일 소유권에 대한 이야기는 아주 설득력 있다.
스타일 면에서 Lobster는 Python과 Crystal의 자식처럼 느껴진다. (Crystal은 타입이 있는 Ruby처럼 보인다.) 이 언어는 들여쓰기로 스코프를 정하고, Ruby와 Crystal처럼 마지막 인자로 전달되는 블록을 허용한다.
Python과 Ruby와 달리 가비지 컬렉터가 없고, Lobster는 컴파일된다. 대신 메모리는 참조 카운팅 방식으로 관리하지만, 저자가 “컴파일 시간 참조 카운팅”이라고 부르는 더 나은 방식을 쓴다. 여기 설명 글이 있다.
Lobster는 게임과 그래픽 애플리케이션 개발에 초점을 맞추지만, 사실 무엇에든 사용할 수 있다. 간단한 게임을 이용해 언어를 가르치는 훌륭한 튜토리얼이 있다. 메모리 관리 시스템을 제외하면 언어 자체는 다른 것들보다 덜 실험적이다. 문법이 새로운 지평을 여는 것은 아니지만, 그럼에도 작은 게임 프로젝트의 플랫폼으로서는 아주 재미있어 보인다.
문서 품질에 대해서는 저자를 칭찬하고 싶다. 완벽하다고 할 수는 없지만 정보량이 매우 많고 이해하기 쉽다. 좋은 언어 레퍼런스, “C 프로그래머용 치트 시트”, 양질의 빌드 안내, 튜토리얼, 메모리 관리 배경 설명 등 다양한 자료가 있다.
이 언어는 아직 개발 초기 단계에 있다. 언어 전체는 구현되었지만 표준 라이브러리는 아직 구축 중이다. 빌드 시스템도 현재는 MVP 수준이다. 그럼에도 불구하고 극히 흥미롭다. Austral은 몇 가지 핵심 기능만 신중하게 고른다는 점에서 독특하다. 특히 선형 타입과 타입 클래스가 그렇다.
Austral은 얼핏 보면 작은 Ada처럼 보인다. 표면적인 문법이 비슷하다. 이는 이 언어의 의도된 용도를 암시한다. Austral은 꽤 읽기 쉬운 문법으로 매우 안전한 프로그램을 만들도록 설계되었다. anti-feature 목록도 길다. Austral은 단순함을 유지한다.
가장 흥미로운 기능은 선형 타입과 타입 클래스다. 선형 타입은 부분적으로 Rust의 borrow-checker 역할을 대신하지만, 더 엄격하기 때문에 오히려 더 많은 안전성을 제공한다. Austral도 borrow checker를 사용하지만 Rust보다 단순하다. 선형 타입은 어휘적 스코프를 사용한다. 선형 타입이란 무엇인가? Rust는 Affine 타입을 사용하는데, 이는 선형 타입보다 더 허용적이며 어쩌면 놀랍게도 추론하고 검사하기는 약간 더 어렵다. 선형 타입은 메모리 안전성뿐 아니라 자원 안전성(열린 파일, 네트워크 연결)까지 전반적으로 다룰 수 있다.
Austral은 타입 클래스 형태로 다형성을 제공한다. 매우 대략적으로 말하자면 타입 클래스는 오버로드된 함수처럼 생각할 수 있지만, 유용한 제약을 두면서도 더 쉽게 모호성을 제거하고 타입 검사를 할 수 있는 방식이다.
현재의 Austral 컴파일러(부트스트래핑용)가 OCaml로 작성되었다는 점도 흥미롭다.
Myrddan은 다른 시스템 언어들 사이에서 정확히 중간쯤에 위치한다. 다른 것들보다 약간 더 오래되었다. 다만 현재도 활발히 유지보수되는지는 잘 모르겠지만 사용은 가능하다.
다른 언어들만큼 V에 대해 많이 알지는 못한다. 홈페이지에서는 다음과 같이 주장한다.
Rust와 Go의 좋은 부분을 어느 정도 빌려온 것으로 보이며, Go보다 조금 더 정교한 타입 시스템을 가지면서도 가비지 컬렉터와 단순한 동시성 지원은 유지하는 듯하다. 내게는 이런 절충이 괜찮아 보인다. JSON 지원이 내장되어 있고, 그 밖의 “batteries included” 라이브러리들도 개발 중인 듯하다. 이미 패키지 관리자도 있다. 현재 릴리스의 품질에 대해서는 내가 말하기 어렵다. (버전은 0.3.3이다.) 작년에는 주장된 기능 중 실제로 얼마나 동작하는지를 두고 온라인에서 다소 논란이 있었다.
C를 V로 변환하는 변환기도 있다. Jakt나 Nim처럼 C 소스를 꽤 쉽게 포함하고 V와 함께 외부 라이브러리를 사용할 수 있을 것이다.
아래 두 개는 내가 방금 우연히 발견한 것이다. 많이 조사할 시간은 없었지만 흥미로워 보여서 적어 둔다.
Cone 이건 정말 멋져 보인다. 내가 읽은 기능들 중 얼마나 구현되었는지는 분명하지 않다. 기능 목록이 포부적이라는 점은 분명히 밝히고 있다. (‘plan.md’는 있지만 자세하지는 않다.) 반면 IDE 지원도 있고 언어 웹 플레이그라운드도 이미 있으며, 전체적으로 꽤 잘 다듬어진 느낌이다. Cone home page
Compis 이건 깔끔한 개념이다. Compis 소스 파일을 C와 섞어 쓸 수 있다. C나 WASM으로 컴파일되며 C 프로젝트를 빌드하는 데 사용할 수 있다. 언어는 Rust와 비슷하게 보이지만 borrow checker는 없다. 대신 소유권으로 메모리를 추적한다. 전반적으로 좋아 보인다. Compis home page.
최근까지는 시스템 개발을 위해 C나 C++를 벗어나고 싶을 때 이런 조금 더 오래된 언어들이 있었다. 모두 실전에서 사용할 수 있다. 이들은 약간의 탈출구와 함께 모두 가비지 컬렉터를 사용한다. 여기서 다룬 새로운 시스템 언어들과 완전히 비교 가능하지는 않지만, 거의 주류에 가깝거나 적어도 주류 안에 있다고 볼 수 있는 가장 가까운 존재였다.
JVM과 Microsoft .NET 언어들은 무거운 런타임 VM이 필요하고 같은 틈새를 채우지 않으므로 제외한다.
Nim : GC 또는 ARC, C 또는 WASM으로 컴파일. Modula-2에 Python식 공백 스코프를 더한 느낌. Nim home.
Crystal: GC. Ruby 같은 문법, 매우 강력한 타입 추론, 유니언 타입. Crystal은 정말 멋지다. Crystal home
Go : GC, 컴파일러가 독립 실행형 바이너리를 만듦, 표준 라이브러리의 좋은 동시성 지원. Google / Alphabet의 지원을 받음. Go home.
D : GC 또는 수동, “더 나은 C” 지원, 순수 함수, 매우 빠른 컴파일러, 멀티패러다임. 자잘하지만 좋은 기능이 많다. D는 멀티패러다임 언어다. “더 나은 C++”와 많이 비슷하지만, 그 이상이기도 하다. D home
마지막으로 Ada를 사용할 수도 있다. 전혀 새로운 언어는 아니지만, 내가 이미 소개한 새로운 시스템 프로그래밍 언어들의 특성을 대부분 갖추고 있으며 C++도 C도 아니다.
Ada는 오래되었다 (1980). 전혀 새롭지 않다.
new
뿐이다. 그래서 그 점에서는 꽤 안전하다. 정말 필요하다면 메모리를 재사용할 수 있다. 언어 설계상 이것이 겉보기만큼 큰 결손 기능은 아니다.
Ada에 대해서는 ‘Random Walk Through Ada’에서 더 읽어 볼 수 있다.
태그: RustCrystalProgramming Languagessoftware Development
Colin Davis • 2026 •ColinsBlog.net
테마 제공: beautiful-jekyll