# Roc 컴파일러의 Rust→Zig 재작성 진행기

> Clean Markdown view of GeekNews topic #31507. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=31507](https://news.hada.io/topic?id=31507)
- GeekNews Markdown: [https://news.hada.io/topic/31507.md](https://news.hada.io/topic/31507.md)
- Type: GN+
- Author: [xguru](https://news.hada.io/@xguru)
- Published: 2026-07-17T07:52:17+09:00
- Updated: 2026-07-17T07:52:17+09:00
- Original source: [rtfeldman.com](https://rtfeldman.com/rust-to-zig)
- Points: 2
- Comments: 2

## Topic Body

- 기존 구현의 **구조적 결함을 해결**하기 위해 Rust 30만 줄을 Zig로 다시 작성했으며, 487일 만에 기능 동등성에 도달해 올해 후반 첫 정식 번호 릴리스인 0.1.0을 목표로 함
- 새 컴파일러는 **핫 코드 로딩**과 재현 가능한 크로스 컴파일, 패턴 매칭 안의 문자열 보간, HTTP 라우팅의 힙 할당 제거를 지원하며 `Rocci Bird`의 wasm 크기도 절반 이하인 31KB로 줄임
- Zig를 선택한 핵심 이유는 빌드 시간, 세분화된 할당자와 데이터 배치 제어, 컴파일러 개발에 적합한 생태계, 메모리 비안전 코드 검사였으며 Zig 0.17.0의 증분 빌드는 약 46만 줄을 **35ms**에 다시 빌드함
- 실제 버그 분류에서 Rust 컴파일러는 메모리 손상 21건, Zig 컴파일러는 10건이었지만 대부분 잘못된 코드 생성 때문이었고, Zig 컴파일러 자체의 메모리 안전성 오류는 파일명을 깨뜨린 **use-after-free 2건**이었음
- Zig는 포인터 없는 데이터 구조, 무파싱 역직렬화, LLVM bitcode 직렬화기 재사용에 잘 맞았지만 테스트의 자동 메모리 해제, 다형성, 비공개 구조체 필드, 죽은 코드 탐지, 릴리스 간 호환성에서는 Rust의 개발 경험이 더 나았음

---

### 기능 동등성에 도달한 재작성
- [Roc](https://www.roc-lang.org/) 컴파일러 팀은 약 1년 반 동안 **Rust 30만 줄**을 [Zig](https://ziglang.org/)로 재작성해 기존 컴파일러와 기능 동등성에 도달함
- 기능 동등성은 중요한 이정표지만 정식 릴리스는 아니며, 새 컴파일러의 **0.1.0**은 올해 후반을 목표로 함
- 2024년 WASM-4 게임 [Rocci Bird](https://github.com/lukewilliamboswell/roc-wasm4/blob/d4161199b0a8afd55d24c30dae304b8a0358f433/examples/rocci-bird.roc)를 새 컴파일러로 빌드할 수 있게 됨
  - 전체 게임은 Roc 코드 1,000줄 미만임
  - [업데이트된 소스](https://github.com/lukewilliamboswell/roc-wasm4/blob/4ec6b695d66530bc9de41bc80b112038e3c1ea12/examples/rocci-bird.roc)는 [원본](https://github.com/lukewilliamboswell/roc-wasm4/blob/a769ade51cbd4613b4fca468764c9034f9c8070c/examples/rocci-bird.roc)보다 간결함
  - `roc build --opt=size`가 생성하는 wasm 바이너리는 **31KB**로, 기존 컴파일러 결과물의 절반보다 작음
- 홈페이지에서는 2.5MB WebAssembly 컴파일러로 기본 Roc 프로그램을 브라우저에서 작성하고 실행할 수 있음
- 재작성에는 **487일**이 걸려 Bun이 Zig 약 50만 줄을 Rust로 옮긴 11일보다 476일 길었음
  - Bun은 직접 포팅했지만 Roc은 여러 컴파일러 구조와 기능을 크게 바꾸는 재작성에 가까웠음
  - 따라서 두 코드베이스의 규모나 기간을 Rust와 Zig만으로 직접 비교하기는 어려움

### 새 컴파일러가 제공하는 개발 경험
- ## 핫 코드 로딩과 크로스 컴파일
  - `roc server.roc`로 서버를 실행한 뒤 코드를 수정하면 다음 요청부터 **새 코드가 자동 적용**됨
  - Python 같은 인터프리터 언어에서는 일반적이지만 Roc 같은 고성능 컴파일 언어에서는 흔하지 않은 동작임
  - 웹 서버뿐 아니라 간단한 2D 게임에서도 같은 방식으로 작동함
  - 배포할 때는 `roc build server.roc`가 LLVM 최적화를 적용한 **독립 실행형 바이너리**를 생성함
  - `roc build --target=x64musl`로 Alpine Linux용 정적 바이너리를 크로스 컴파일할 수 있음
  - 동일한 소스 바이트를 입력하면 Mac을 포함한 어느 빌드 시스템에서도 **동일한 출력 바이트**를 생성함
- ## 패턴 매칭 안의 문자열 보간
  - `"/users/${id}"` 같은 문자열 보간을 **패턴 매칭** 안에서 지원함
  - Express식 라우팅처럼 실행 중 템플릿 문자열을 파싱하지 않고 컴파일러가 직접 처리함
  - HTTP 메서드와 경로를 함께 매칭하고, 중첩 경로나 기본값도 패턴으로 분기할 수 있음
  - 예시의 전체 HTTP 요청 처리 코드는 컴파일 시 타입 안전성을 검사하면서 **힙 할당을 전혀 수행하지 않음**
  - 순수 함수의 컴파일 시 실행을 이용해 HTTP 요청 라우팅을 무할당으로 구현했으며, 홈페이지의 WebAssembly 컴파일러에서 문법을 시험할 수 있음

### 처음부터 다시 작성한 이유
- Roc은 Rust·C·Zig와 달리 시스템 언어가 아니며, **참조 카운팅 기반 자동 메모리 관리**를 사용함
  - 추적식 가비지 컬렉터의 일시 중지를 피함
  - [Perceus 최적화](https://www.microsoft.com/en-us/research/wp-content/uploads/2020/11/perceus-tr-v4.pdf)와 Koka식 기회적 변경을 활용함
- 일반적인 비시스템 언어처럼 클로저 캡처마다 힙을 할당하지 않고, [람다 집합 특수화를 통한 다형적 비함수화](https://www.cs.princeton.edu/~mpmilano/publication/lss/)를 사용함
- 비함수화는 함수형 언어에서 인라이닝처럼 여러 후속 최적화를 가능하게 하지만, 기존 구현을 정확히 만드는 일은 매우 어려웠음
- [Ayaz Hafiz의 OCaml 프로토타입](https://github.com/ayazhafiz/cor/)을 통해 문제가 여러 컴파일러 단계에 걸친 **구조적 결함**이며, 해결하려면 컴파일러 대부분을 다시 작성해야 한다는 점을 확인함
- 다른 기여자들도 각기 다른 이유로 여러 부분을 다시 작성할 계획이어서, 거의 전부를 점진적으로 교체하는 테세우스의 배 방식 대신 전체 재작성을 검토하게 됨
- 성공한 컴파일러 프로젝트에서는 자체 호스팅 등을 위해 처음부터 재작성하는 사례가 흔하며, 자체 언어가 아닌 Go로 옮긴 [TypeScript 재작성](https://devblogs.microsoft.com/typescript/typescript-native-port/) 사례도 있음
- Roc 컴파일러는 자체 호스팅하지 않는다는 방침이지만, 이번에는 재작성으로 얻는 이점이 알려진 비용보다 크다고 판단함

### 다시 Rust가 아닌 Zig를 선택한 기준
- 팀은 이미 표준 라이브러리의 여러 기본 기능에 Zig를 사용하고 있었고, 충분히 잘 아는 시스템 언어가 **Rust와 Zig**뿐이어서 두 언어만 진지하게 검토함
- 프로젝트마다 적합한 언어가 다르며, Rust를 다른 업무에서 계속 사용하는 것과 Roc에 Zig를 선택하는 일은 모순되지 않음
- ## 빌드 시간
  - Rust의 `cargo` 빌드는 증분 빌드까지 오래 걸렸으며 코드베이스가 커질수록 주요 불편으로 남았음
  - Zig로 옮기면 빌드가 훨씬 빨라질 것으로 예상함
- ## 메모리와 데이터 배치 제어
  - 컴파일 단계마다 다양한 할당자, 특히 **아레나 할당자**를 사용하고 구조체 배열(SoA) 배치를 광범위하게 활용함
  - Rust 생태계는 대체로 하나의 전역 할당자를 가정하지만, Zig 생태계는 세분화된 할당자 전달을 기본으로 삼고 SoA 지원도 표준으로 제공함
- ## 필요한 생태계의 범위
  - Rust 전체 생태계는 Zig보다 크지만, Roc의 특수한 요구와 관련된 패키지는 두 생태계 모두 많지 않았음
  - LLVM C++ 라이브러리를 감싸는 대신 빠르게 bitcode를 생성하는 코드처럼 필요한 틈새 기능은 Zig 쪽에 더 많았음
- ## 메모리 비안전 코드 지원
  - 기존 Rust 컴파일러 30만 줄에는 약 **1,200개의 `unsafe` 사용**이 있었음
  - 비교 대상으로 Rust 컴파일러 자체는 350만 줄에서 약 4만 개의 `unsafe`를 사용함
  - 기계어를 생성하는 컴파일러에서는 메모리 비안전 작업이 중요한 업무 일부임
  - Rust는 드문 `unsafe` 블록을 격리하고 Miri나 Valgrind로 검사하는 모델이지만, Roc에서는 `unsafe`가 드물지 않았음
  - Zig는 메모리 비안전 코드를 올바르게 작동시키기 위한 기능을 더 제공했고, 팀은 바로 이 영역에서 가장 많은 지원을 원했음

### borrow checker 없이 얻은 메모리 안전성
- ## Rust와 Zig의 검사 범위
  - Microsoft의 2019년 자료에 따르면 매년 보안 업데이트로 처리되는 취약점의 약 **70%가 메모리 안전성 문제**였음
  - 해당 자료의 2018년 분류를 Rust와 Zig 관점에서 나누면 다음과 같음
  - 83.6%는 범위 밖 읽기·쓰기, 안전하지 않은 캐스트, 초기화되지 않은 읽기, 스택 오버플로, 비메모리 안전성 문제로, Rust와 Zig 선택에 영향을 받지 않는 범주임
  - 16.4%는 use-after-free이며 Rust의 borrow checker, Zig `ReleaseSafe`, Fil-C 방식 검사로 잡을 수 있는 범주임
  - Zig의 [`ReleaseSafe`](https://ziglang.org/documentation/master/#toc-ReleaseSafe)는 해제된 메모리를 사용하면 실행 중 패닉을 발생시킴
    - Rust의 안전한 부분집합보다 검사가 덜 포괄적임
    - 실행 비용이 있고 프로그램이 패닉할 수 있음
  - [`ReleaseFast`](https://ziglang.org/documentation/master/#toc-ReleaseFast)는 프로덕션에서 검사를 생략하지만 디버그 빌드와 테스트에서는 유지함
  - 모든 실제 실행 경로를 테스트한다면 `ReleaseSafe`와 같은 안전성을 얻을 수 있지만, 그런 테스트 범위는 일반적으로 현실적이지 않음
- ## 다른 Zig 프로젝트와 Rust의 `unsafe`
  - [TigerBeetle](https://tigerbeetle.com/)는 `ReleaseSafe`를 사용하며, 정밀한 [Jepsen 검증](https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-meet-jepsen/)에서 안전성 버그 2건이 발견됐지만 둘 다 메모리 안전성과 무관했음
  - `ReleaseFast`를 사용하는 Ghostty와 Zig 컴파일러도 Zig 코드의 메모리 비안전성으로 발생한 CVE가 없음
  - Rust 프로그램도 의존성 내부의 `unsafe`를 통해 메모리 안전성 공백이 생길 수 있음
  - Unsafe Rust에는 `ReleaseFast` Zig와 같은 위험이 있지만, 개발 중 문제를 잡아내는 Zig의 실행 검사에 해당하는 기능은 없음
  - Miri와 Valgrind가 도움을 줄 수 있지만 이를 사용하는 Rust 프로젝트는 많지 않음
  - 대신 `unsafe`를 드물게 사용하고 더 엄격히 검토하는 문화가 실무에서 Rust의 강한 메모리 안전성 평판을 만듦
  - Rust 기반 프로젝트에서도 `unsafe` 관련 취약점이 발생한 사례가 있음
    - Deno에는 범위 밖 읽기와 use-after-free CVE가 있었음
    - Rocket에는 use-after-free CVE가 있었음
    - Actix는 `unsafe` 사용량이 비정상적으로 높던 시기에 여러 메모리 비안전성 CVE가 발생함
  - Roc은 할당 대부분이 수명이 단순한 아레나에서 일어나므로 use-after-free를 큰 위험으로 보지 않았고, Zig의 추가 검사가 본질적으로 비안전한 코드에 더 유용하다고 판단함

### 재작성 후 확인한 메모리 손상 버그
- Claude Opus 4.8로 Roc 이슈 트래커를 분류한 결과는 다음과 같음

| 컴파일러 | 메모리 손상 발생 | 메모리 손상 없음 | 전체 |
|---|---:|---:|---:|
| Rust | 21 | 2,575 | 2,596 |
| Zig | 10 | 421 | 431 |

- Rust 컴파일러의 메모리 손상 21건은 컴파일러 내부 로직의 손상이 아니었음
  - borrow checker는 의도한 역할을 수행함
  - 잘못 생성된 기계어가 컴파일된 프로그램에서 메모리를 손상시킨 **오컴파일** 버그였음
- Zig 컴파일러의 메모리 손상 10건 중 8건도 오컴파일이었음
- 나머지 2건은 오류 보고 코드의 use-after-free였음
  - `roc check`와 `roc bundle`의 오류 메시지에서 파일명이 U+FFFD 대체 문자로 깨졌음
  - Rust borrow checker였다면 두 버그를 모두 잡을 수 있었음
- 다른 도구 선택이 실제 사용자에게 미쳤을 결과는 다음과 같음

| 도구 선택 | 실제 메모리 안전성 영향 |
|---|---|
| Zig `ReleaseFast` | 일부 오류 메시지에서 파일명이 렌더링되지 않는 버그 2건 |
| Zig `ReleaseSafe` | 일부 오류가 패닉하고 파일명을 렌더링하지 못하는 버그 2건 |
| Rust borrow checker | 두 버그 모두 방지 |

- 18개월, 수십만 줄, 수백 건의 버그 보고를 고려하면 세 선택지의 차이는 프로젝트에 실질적으로 크지 않았음
- Bun은 JavaScript의 추적식 가비지 컬렉션 값과 수동 관리 값을 함께 다루면서 use-after-free, double-free, 해제 누락이 큰 비중을 차지했음
- Roc 컴파일러는 JavaScript나 다른 추적식 가비지 컬렉터와 연동하지 않으므로 같은 수명 관리 문제를 겪지 않음
- Roc에는 컴파일러 내부 메모리 오류보다 **생성된 출력 코드의 메모리 오류**를 찾는 도구가 더 필요하며, 후자는 borrow checker의 범위 밖임

### 빌드 시간의 실제 결과
- `zig build --watch -fincremental`은 현재 약 45만~46만 줄의 Zig 코드에서 변경 사항을 약 **35ms**에 다시 빌드함
- 안정 버전 Zig 0.16.0에는 Roc 코드베이스에서 `-fincremental`을 깨뜨리는 버그가 있음
  - 수정 사항은 반영됐지만 이를 사용하려면 호환성이 깨지는 Zig 0.17.0 사전 빌드로 옮겨야 함
  - 관련 의존성도 함께 벤더링하고 0.17.0으로 업그레이드해야 하므로 다음 안정 릴리스를 기다리기로 함
- Intel 데스크톱과 Ubuntu 26에서 측정한 결과는 다음과 같음

| Roc 컴파일러 | 코드 규모 | 콜드 빌드 | 증분 빌드 |
|---|---:|---:|---:|
| Rust 1.85.0 기반 원본 | 354K | 32.4초 | 10.0초 |
| Rust 1.97.0 기반 원본 | 354K | 25.4초 | 3.4초 |
| Zig 0.16.0 기능 동등성 시점 | 320K | 39.6초 | 8.6초 |
| Zig 0.17.0 현재 재작성본 | 464K | 32.1초 | 0.035초 |

- 기능 동등성 시점에는 거의 변하지 않는 산출물도 매번 다시 빌드했지만, 현재는 필요할 때만 생성함
  - 이 변경으로 코드가 약 50% 늘었는데도 콜드 빌드는 더 빨라짐
- Rust 1.85.0에서 1.97.0으로 넘어가며 증분 빌드는 10초에서 3.4초로 줄어들어 18개월 동안 약 3분의 2가 개선됨
- Zig의 35ms는 3.4초의 약 **100분의 1**이며, Rust 측정 코드보다 약 50% 큰 코드베이스에서 나온 결과임
- 현재 `-fincremental`은 x86-64에서만 작동하고 많은 기여자가 ARM 기반 Mac을 사용하므로 아직 빌드 시간 이점을 온전히 활용하지 못함

### 포인터 없는 구조와 무파싱 역직렬화
- 새 디스크 캐시는 Zig 컴파일러와 게임 개발에서 쓰이는 방식처럼 실행에 효율적인 메모리 배치를 그대로 디스크 형식으로 사용함
- 모든 컴파일러 데이터 구조는 포인터 대신 **32비트 인덱스 배열**로 표현되며, 여러 곳에서 구조체 배열 형식을 사용함
  - 메모리 사용량을 줄이고 실행 속도를 높임
  - 별도 직렬화 형식으로 바꾸지 않고 데이터 구조를 디스크에 직접 기록할 수 있음
- 역직렬화할 때는 디스크 바이트를 파싱하지 않음
  - 바이트를 메모리에 읽음
  - 기존 데이터 구조가 새 배열을 가리키도록 일부 재배치함
  - 이후 즉시 사용할 수 있음
- 속도는 사실상 디스크에서 메모리로 바이트를 읽는 I/O 속도로 제한됨
  - 운영체제 디스크 캐시에 데이터가 있으면 대략 `memcpy` 속도로 이전 빌드 결과를 불러옴
- `roc check`는 첫 실행에서 파싱·타입 검사 등의 결과를 디스크에 저장함
  - 입력 소스가 바뀌지 않았다면 두 번째 실행에서는 데이터 구조를 디스크에서 메모리로 바로 옮김
- `roc test`는 결정적인 순수 함수 테스트 결과도 캐시함
- 캐시는 파일 단위로 동작하므로 한 파일을 바꾸면 해당 파일과 의존 파일만 다시 처리함
- 이 방식은 컴파일러 전체가 포인터 대신 인덱스를 사용하기 때문에 가능하며, 일반적인 포인터 중심 구조에서는 **무파싱 역직렬화**가 불가능함
- ## 인덱스 기반 구조의 안전성 한계
  - 포인터가 잘못된 주소를 가리킬 수 있듯 인덱스도 잘못된 배열을 조회해 임의의 바이트를 읽을 수 있음
  - Rust borrow checker는 포인터 수명을 다루지만 어떤 인덱스가 어떤 배열에 속하는지는 검사하지 않음
  - 필요한 배열 수를 사전에 안다면 Rust의 [`compact_arena`](https://docs.rs/compact_arena/0.5.0/compact_arena/)가 매크로로 타입 태그를 만들어 잘못된 배열 조회를 막을 수 있음
  - Roc처럼 모듈 수에 따라 배열 수가 달라지면 이 기법을 적용할 수 없어 `compact_arena`도 `SmallArena::new`를 `unsafe`로 표시함
  - 빈 아레나 생성 자체는 위험을 만들지 않지만 실제 위험은 매우 자주 수행하는 배열 인덱싱에 있음
  - Safe Rust는 `unsafe`가 작고 격리돼 있다는 가정에서 효과적이지만, Roc처럼 `unsafe`가 광범위하면 이 가정이 성립하지 않음

### Roc에 맞았던 Zig 생태계
- Bun은 JavaScript와 수동 메모리의 상호 운용 때문에 정리 코드를 한 번만 실행하는 Rust의 `Drop`이 유용했음
- Roc은 반대로 모듈과 컴파일 단계마다 **별도 아레나**를 사용하려 하므로, 전역 할당자와 암묵적 `Drop`을 전제로 한 Rust 패키지가 불편했음
- Zig 생태계는 할당자를 명시적으로 전달하는 API가 일반적이어서 Roc의 메모리 관리 방식과 잘 맞음
- Rust 생태계는 Bun이 원하는 구조에, Zig 생태계는 Roc이 원하는 구조에 각각 더 적합했음
- ## LLVM bitcode 직렬화기 재사용
  - LLVM은 Roc 최적화기의 핵심 의존성이며, Roc 자체 최적화 뒤에 추가 최적화를 수행함
  - LLVM은 주요 API 호환성을 자주 깨뜨려 버전 업그레이드에 상당한 시간과 비용이 필요했음
  - LLVM의 직렬화된 **bitcode 형식**은 안정적이고 하위 호환되므로, 자체 직렬화기를 사용하면 C++ API 변경에서 벗어날 수 있음
  - 이를 위해서는 LLVM C++ 라이브러리와 분리된 수작업 bitcode 직렬화기가 필요함
  - 기존에 알려진 구현은 Zig 컴파일러에 있었고, Roc의 새 컴파일러는 해당 Zig 코드를 재사용함
  - Roc이 Zig 생태계에서 얻는 가장 큰 의존성 원천은 일반 패키지보다 **Zig 컴파일러 자체**임

### Zig에서 그리운 Rust 기능
- 컴파일러 구현에서는 명시적 할당 제어가 필요하지만 테스트에서는 Rust의 **자동 할당·해제**가 더 편리했음
  - Zig 테스트 할당자는 메모리 누수를 찾아내고 컴파일된 Roc 코드의 누수도 감지할 수 있음
  - 대신 각 테스트에서 `init`과 `defer deinit`을 정확히 작성해야 하며, 하나라도 잘못되면 누수로 테스트가 실패함
- Zig의 `comptime`이 매개변수적·임시 다형성과 겹치지만 두 형태의 다형성이 그리움
  - Rust의 `Allocator` trait은 `self`를 받을 수 있음
  - Zig의 `ArenaAllocator` 같은 구현은 `anyopaque` 포인터를 받은 뒤 자기 타입으로 캐스팅해야 함
- **비공개 구조체 필드**가 없어 직접 접근하면 안 되는 필드를 컴파일 오류로 막을 수 없음
  - 코드 차이 검토에서는 필드 접근만 보이고 원래 구조체의 문서는 보이지 않으므로 매번 별도로 확인해야 함
- 함수·변수·상수가 모두 `snake_case`를 사용하는 Rust의 일관성이 때때로 그리움
- `unsafe`와 borrow checker는 비용도 있었지만 특정 문제를 `unsafe` 블록 안에서만 걱정하게 해주는 안정감이 있었음
  - Zig에 같은 기능을 추가해야 한다는 입장은 아님
- Zig에서는 Rust보다 **죽은 코드**를 뒤늦게 발견하는 일이 많았음
  - Zig 내장 도구와 TigerBeetle의 `tidy.zig`도 일부 죽은 코드를 잡지 못함
  - 죽은 코드는 바이너리에 생성되지 않아 사용자에게 영향을 주지 않지만 코드베이스 관리에는 불리함
- Rust는 소수 버전 업그레이드와 에디션 변경이 대부분 수월했음
- 현재 Zig는 하위 호환성을 목표로 하지 않으며 예상했던 조건이라 큰 문제는 아니었지만, Rust의 간단한 업그레이드 경험은 더 나았음

### Zig에서 만족한 부분
- Zig는 함수형 프로그래밍처럼 익숙한 도구를 줄이는 대신 다른 속성을 얻는 **감산적 설계**의 매력이 있음
- 매크로가 없으며, 매개변수적 다형성을 포함한 많은 문제를 `comptime`이나 일반 함수로 해결할 수 있음
- 데이터 배치를 세밀하게 제어할 수 있음
  - `u7`, `u5`처럼 2의 거듭제곱이 아닌 정수 타입을 별도 비트 처리 없이 사용함
  - packed struct를 기본 지원함
  - 선언 위치가 아니라 호출 위치에서 함수를 인라인할 수 있음
  - Rust에서는 매크로 기반 크레이트가 필요한 기능을 추가 의존성 없이 이용함
- Zig 빌드 도구 체인은 Alpine Linux와 WebAssembly용 **독립 실행형 바이너리** 생성에 잘 맞았음
  - Roc 표준 라이브러리에 해당하는 builtins를 불투명한 바이너리 블롭으로 컴파일해 최종 실행 파일에 포함하는 특수한 빌드도 처리함
  - Uber도 Zig 언어를 사용하지 않으면서 빌드 인프라에 Zig 도구 체인을 사용함
- Zig의 오류 처리에서는 실패한 힙 할당도 일반 사용자 공간 오류로 다룸
- Roc도 익명 합 타입과 페이로드를 이용해 오류가 자연스럽게 누적되는 유사한 전략을 사용함
- Rust의 `anyhow`, `thiserror`, 기본 `Result` 기반 처리보다 Zig와 Roc의 방식을 선호함
- 오류 전파 문법은 Zig의 `try`보다 Rust의 후위 `?`를 선호해 Roc에도 **후위 `?` 연산자**를 채택함
- 세분화된 할당자 API와 고성능 컴파일러용 재사용 코드를 포함해, 프로젝트 전체로는 Zig 선택에 매우 만족함

### Roc의 다음 단계
- 새 컴파일러의 **0.1.0**을 올해 후반에 출시할 계획이며, Roc 최초로 번호가 붙은 릴리스가 됨
- 출시 전에도 [Nightly 빌드](https://roc-lang.org/install/)를 시험할 수 있지만 현재는 여러 버그, 미완성 기능, 불완전한 문서가 남아 있음
- [Roc Programming Language Foundation](https://roc-lang.org/foundation)은 미국의 501(c)(3) 비영리단체이며, 기부금은 주로 기여자 보상에 사용함
- 향후 개발 진행과 질문은 [Roc Zulip](https://rtfeldman.com/roc.zulipchat.com/)에서 확인할 수 있음

## Comments



### Comment 61936

- Author: neo
- Created: 2026-07-17T09:02:38+09:00
- Points: 1

###### [Lobste.rs 의견들](https://lobste.rs/s/axdfjx/how_our_rust_zig_rewrite_is_going) 
- 수치상 **Zig의 35ms**는 Rust의 3.4초보다 100배 가까이 빠르고 코드도 약 50% 더 많지만, 실제 개발에서는 그 차이가 과장된 듯함  
  컴파일러를 매분 다시 빌드하지 않고 10분마다 빌드한다면 절약되는 시간은 약 3초이며, 3.4초도 충분히 빠름  
  코드베이스가 커지면 Rust가 느려질 수 있지만 **콜드 빌드 시간**은 오히려 악화됐고, 2년마다 노트북을 교체하면서 컴파일러 자체의 개선까지 더하면 Rust의 빌드 시간이 장기적으로 계속 증가한다고 단정하기 어려움
  - 저장하자마자 다음 키를 누르거나 편집 위치를 옮기기도 전에 **컴파일 오류와 무효화된 테스트 결과**가 나타나는 것은 엄청난 이점임  
    Rust의 `check` 모드와 LSP가 전체 재컴파일보다 빠르지만 같은 수준은 아님
  - 10분마다 한 번만 재컴파일한다고 가정하면 차이를 과소평가하게 됨  
    `--watch -fincremental` 조합을 사용하면 저장할 때마다 재컴파일해 매우 빠르고 빈번하게 피드백을 받을 수 있음  
    개인 프로젝트를 Rust에서 Zig로 옮겼고 Rust도 수년간 업무에 사용해 봤는데, **Zig의 컴파일 속도**는 정말 숨통이 트이는 변화였음

- **35ms**라니 놀라울 정도로 빠름  
  재링크만 해도 그보다 오래 걸릴 것 같은데 컴파일러가 실제로 무엇을 하는지 궁금함
  - Zig에는 [자체 링커](https://github.com/ziglang/zig/pull/25299)가 있음
  - 핵심은 **증분 링크**와 기존 바이너리를 제자리에서 수정하는 방식이며, Roc 컴파일러에서는 이를 외과적 링크(surgical linking)라고 불렀던 것으로 기억함  
    함수 구현을 바꾸면 새 어셈블리를 기존 바이너리에 삽입하면 되지만, 인라이닝·함수 시그니처 변경·의존성·공간 부족 시 재배치 등은 추가 분석이 필요함
  - Zig 팀에서 증분 컴파일 작업을 많이 담당했으며, 새 **ELF 링커**는 아직 미완성이지만 개별 함수와 전역 변수 단위의 증분 링크를 목표로 설계됐음  
    함수를 수정하거나 추가하면 출력 실행 파일의 `.text` 섹션에서 충분히 큰 빈 영역을 찾아 새 기계어를 기록함  
    공간이 부족하면 `.text`를 확장하고 다른 데이터를 옮겨야 할 수 있지만, 섹션을 지수적으로 확장해 비용을 분산함  
    필요하면 심볼 테이블과 재배치 항목도 추가하며, 이들을 위한 빈 공간도 미리 남겨 두므로 작업 후 파일을 닫으면 끝남  
    최근 본 Tracy 결과를 기준으로 추정하면 전체 35ms 중 링커가 사용한 시간은 **약 1ms**에 불과함

- 30만 줄의 Rust 코드에서 `unsafe`를 약 1,200번 사용했다는 수치는 예상보다 많음  
  예를 들어 [Inko](https://inko-lang.org/)에는 `unsafe { ... }` 표현식이 162개, C ABI를 통해 생성 코드에 노출되는 `unsafe` 함수가 87개뿐이며 전체 Rust 코드는 약 **8만 8천 줄**임  
  다만 [Inkwell](https://github.com/TheDan64/inkwell)의 동작 방식 때문에 LLVM 백엔드 전체가 사실상 거대한 `unsafe` 영역이어서 단순 비교로 결론 내리기는 어려움  
  나는 포인터를 직접 다루는 것처럼 실제 메모리 안전성을 해치는 함수만 `unsafe`로 표시하지만, 다른 개발자는 패닉을 피하려면 특정 작업을 먼저 해야 한다는 힌트로 표시하기도 함

- Rust 표준 라이브러리와 컴파일러에서 `unsafe`가 **4만 번** 등장한다는 수치는 부정확함  
  테스트와 주석에 나온 단어까지 센 결과이고, 대부분은 표준 라이브러리에 있으며 컴파일러 자체에서는 주석과 테스트를 포함해도 2천 번 미만임  
  rustc에 기여하는 동안 내 PR 중 `unsafe`가 포함된 비율은 1%도 되지 않았을 만큼 컴파일러 내부의 안전하지 않은 코드는 드묾  
  Rust 전체가 의존하는 기초 런타임을 구현하는 표준 라이브러리에 `unsafe`가 많은 것은 자연스러우며, 이런 코드는 어떤 언어에서도 명시적이든 암묵적이든 안전하지 않음  
  해당 컴파일러는 rustc보다 약 10배 작은데 `unsafe` 사용량은 비슷하므로 만연했다고까지 하기는 어렵지만 자주 마주치게 되며, rustc보다 훨씬 많이 필요한 이유가 궁금함
  - 우리 코드베이스도 컴파일러와 표준 라이브러리가 섞여 있고 일부 표준 라이브러리는 **컴파일러 내장 함수**로 구현되므로, 해당 지표에서는 비슷한 대상을 비교했다고 봄  
    양쪽 코드베이스에서 표준 라이브러리 관련 `unsafe`를 따로 분석하지는 않았지만, 새 컴파일러를 Rust로 구현했다면 캐싱과 포인터 대신 인덱스를 사용하는 구조 때문에 rustc보다 `unsafe`가 많았을 것으로 예상함  
    Rust 팀의 작업을 폄하하려는 의도는 없었고, 다른 프로젝트의 성과를 존중하면서 우리의 선택과 진행 상황을 밝히려던 것이었음

- Rust와 Zig 각각의 장단점을 숨기지 않고 균형 있게 평가한 글이며, 18개월간 수십만 줄을 작성하고 수백 건의 버그를 처리한 뒤에도 선택지 중 다른 언어를 골랐다고 프로젝트 결과가 크게 달라지지는 않았으리라는 결론이 특히 솔직함  
  다만 Roc이나 rustc처럼 기계어를 생성하는 컴파일러에서 **메모리 비안전 작업**이 업무의 큰 부분이라는 설명은 이해하기 어려움  
  OCaml이나 Haskell로 작성된 컴파일러도 많고, 기계어 생성 자체는 바이트를 벡터에 구성해 파일로 쓰는 일이므로 안전하지 않을 이유가 없음  
  인터프리팅이나 JIT 컴파일이라면 이해되지만 일반적인 컴파일에도 필요한 이유가 궁금함
  - 기계어를 생성하는 것 자체는 단순히 바이트를 기록하는 일이므로 안전하지 않다는 표현은 부정확했음  
    위험은 생성된 기계어를 실행할 때 생기며, 실제 컴파일러가 기계어를 생성하는 동시에 실행하는 경우가 많아 **업무의 큰 부분**이라고 표현했음  
    인터프리팅과 JIT 외에도 Rust의 `const fn`이나 Roc에서 최상위로 끌어올릴 수 있는 표현식처럼 컴파일 시점에 사용자 코드를 평가하거나, 테스트를 실행한 뒤 출력을 검사해 사용자에게 표시할 내용을 정하는 작업 등이 해당함
  - Zig 컴파일러처럼 매우 빠른 **증분 컴파일러**를 만들려면 저수준 언어와 상당히 안전하지 않은 작업이 필요하다는 의미로 보임
  - 글에서는 잘못된 컴파일로 메모리 안전성 버그가 생긴 경우도 **컴파일러의 메모리 안전성 버그**로 계산함  
    손상된 메모리가 컴파일러 프로세스에 있든 생성된 프로그램에 있든, 프로세서가 잘못된 동작을 한 원인은 컴파일러가 만든 명령이며 수정해야 할 곳도 컴파일러 코드라는 기준임
  - Roc은 컴파일러를 Rust로 작성하던 시기에도 런타임과 표준 라이브러리에는 Zig를 사용했음  
    외부 링크 코드와 가비지 컬렉터 같은 구성 요소는 Rust에서도 `unsafe`를 많이 필요로 해 안전한 Rust의 장점을 상당 부분 상쇄함  
    컴파일러만 안전한 언어로 작성할 수는 있지만 성능이 문제이며, Zig와 Roc 컴파일러는 **배열 구조(SoA)** 및 포인터 대신 배열 인덱스를 널리 사용함  
    이를 Rust로 구현하면 빌림 검사기를 우회하게 되어 관련 안전성 이점을 잃게 됨  
    컴파일러의 수명 관계는 의외로 단순해 한 단계에서 아레나에 데이터를 할당·생성·수정하고, 다음 단계에 읽기 전용으로 넘긴 뒤 아레나 전체를 폐기할 수 있음  
    더 복잡한 부분은 디스크에서 상태를 읽고 바이너리를 제자리에서 수정하는 증분 컴파일과 링크이며, 이 과정에서는 상태 손상·버그·잘못된 컴파일·메모리 문제를 일으킬 수 있지만 컴파일러 프로세스 자체의 메모리 안전성과는 별개임  
    **안전성과 정확성**은 프로그램 내부의 메모리 안전성보다 훨씬 넓은 개념이며, 특히 Rust로 표현하기 어려운 작업을 안전하고 정확하게 수행하려면 더욱 그러함

- `compact_arena` 제작자로서 소개된 것은 반갑지만, 이 라이브러리의 `unsafe` 사용 방식이 잘못 묘사됐음  
  `compact_arena`의 목적은 안전한 Rust에서 `new`를 오용할 수 없도록 보장해 **인덱싱을 안전하게 만드는 것**임  
  `mk_arena` 매크로는 필요한 아레나 개수를 알 수 없는 반복문 안에서도 안전한 Rust 코드에서 호출할 수 있음
  - `new`가 안전하게 사용된다는 설명을 이해하지 못했을 수도 있지만, https://docs.rs/compact_arena/0.5.0/compact_arena/struct.SmallArena.html#method.new 의 안전성 섹션에는 생성자에 전달하는 태그가 인덱싱 기법의 기반이며, 이 값을 다른 아레나에서 사용하면 두 아레나의 인덱스가 섞여 범위 밖 접근과 **정의되지 않은 동작**으로 이어질 수 있다고 적혀 있음  
    내 요지는 `new()` 호출 자체가 아니라 `new()`로 만든 값에 인덱싱할 때 위험이 발생한다는 것이며, 감사하고 `unsafe`로 표시해야 할 곳도 실제 인덱싱 호출부라고 봄  
    다만 설계를 잘못 이해했을 가능성은 있음

- Python은 새 코드를 반영하려면 프로그램을 재시작해야 하고, **핫 리로딩**에는 비표준 확장 기능과 신중한 코드 작성이 필요한 것으로 알고 있음  
  핫 리로딩은 Lisp나 Smalltalk 같은 이미지 기반 개발 환경 또는 Erlang에서 더 일반적임
  - `importlib.reload()`를 사용하면 Python에서도 핫 리로딩이 가능하지만, 얼마나 널리 쓰이는지는 모르겠음

- `cargo build`를 사용하지 않으면 **빌드 시간**을 줄일 수 있는지 궁금함  
  Bazel을 구성하는 작업이 Zig로 이식하는 것보다 더 큰지 작은지는 불확실하며, 물론 빌드 시간만이 언어 전환의 이유는 아니었음

### Comment 61934

- Author: neo
- Created: 2026-07-17T07:52:18+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=48933149) 
* 글 전반은 괜찮지만, Roc이나 rustc처럼 기계어를 생성하는 컴파일러에서 **메모리 비안전 작업**이 업무의 큰 부분이라는 표현에는 동의하기 어려움  
  실행 중 바이너리 패치나 코드 재적재에는 비안전 코드가 필요하겠지만, 평범하게 실행 파일을 만드는 과정에서 기계어 생성 자체가 비안전할 이유는 없음  
  오히려 언어의 **런타임**에서 비안전 코드를 발견할 가능성이 큼
  * 동의함. 기계어 생성은 바이트를 기록하는 작업일 뿐이고, 잠재적 비안전성은 그 기계어를 실행할 때 생김  
    다만 실제로는 많은 컴파일러가 기계어를 생성하면서 직접 실행하기도 해서 “업무의 큰 부분”이라고 표현했지만, 컴파일러가 반드시 두 작업을 모두 해야 하는 것은 아님  
    바이너리 패치, 코드 재적재, 런타임뿐 아니라 Rust의 `const fn`이나 Roc에서 최상위로 끌어올릴 수 있는 표현식처럼 **컴파일 시점에 사용자 코드 평가하기**, 테스트를 실행하고 출력을 검사해 표시 내용을 결정하는 작업 등을 염두에 뒀음
  * 메모리 안전 언어에도 비안전 코드 블록이 있다는 사실을 비틀어 “그렇다면 메모리 안전성이 무슨 소용인가”라고 결론 내리는 경우가 많음  
    안전벨트를 매도 머리를 부딪칠 수 있으니 안전벨트는 성가실 뿐 사용하지 말아야 한다는 논리와 비슷함
  * 기계어 생성에 비안전 작업이 본질적으로 필요한 것은 아니지만, 여기에는 **서로 다른 우선순위**가 반영된다고 봄  
    극단적인 고성능 코드에서는 자료구조와 알고리즘, 메모리 할당 전략부터 달라지며, TigerBeetle은 시작할 때 메모리를 한 번에 모두 할당하는 것으로 유명함  
    Roc 컴파일러도 Zig와 비슷한 절충을 택하려 하므로 여러 공통 패턴이 발견되는 것은 자연스러움
  * 기계어 생성에 비안전 작업이 필요하다는 말은 확실히 틀렸음. 컴파일러는 완전히 추상화된 자료구조만으로도 작업할 수 있으며, 굳이 메모리 비안전 작업이 필요할 만한 곳은 **링커**에 더 가까움
  * 실제로 기계어를 만들기 위해 컴파일러의 어느 부분에서 메모리 비안전 연산이 필요한지 이해하기 어려움

* `ReleaseSafe`가 런타임 검사로 **해제 후 사용(use-after-free)** 을 잡는다는 주장에는 근거가 보이지 않음  
  Zig 문서에서 런타임 메모리 안전 검사를 조사했지만 `use-after-free`, `UaF`, `safety-checked`로 검색해도 관련 내용을 찾지 못했으며, 릴리스 빌드에서 `DebugAllocator`를 쓰더라도 이를 안정적으로 검출하지는 못함  
  관련 글은 [https://landaire.net/memory-safety-by-default-is-non-negotia...](<https://landaire.net/memory-safety-by-default-is-non-negotiable/>)에 정리했음
  * Zig 코드를 많이 작성해 본 입장에서, 그런 기능이 있더라도 내 코드에서는 제대로 작동한 적이 없음  
    인공지능 이전에 직접 코드를 작성하며 얻은 판단이고, Zig와 LLM의 조합에서는 무언가 달라질 수도 있겠지만 글을 읽을수록 이상하게 표현된 주장들이 더 보여 신뢰하기 어려워짐  
    진솔한 기술적 판단이라기보다 기존 논쟁을 정당화하려고 쓴 글처럼 읽히지만, 특이한 글과 언어를 좋아하고 과도한 인공지능 열풍에도 반감이 있어 일단 선의로 보려 함
  * `ReleaseSafe`는 **경계 검사**를 추가하고 도달 불가능 코드에서 패닉을 일으키는 정도로 알고 있음  
    Zig는 시간적 메모리 안전성(temporal memory safety)을 제공하지 않는 것으로 보임

* 성숙한 OCaml이 유연하고 표현력이 충분해 시제품 검증에는 쓰였지만 최종 구현 언어로 선택되지 않은 점이 흥미로움  
  Zig의 **증분 빌드**가 dune보다 유의미하게 빠를지도 의문이며, 크로스 컴파일이 장점인데도 “왜 Zig인가”에서는 다루지 않았음  
  컴파일러에 세밀한 메모리 제어가 정말 중요한지, OCaml로 시작했던 Rust와 WASM처럼 어느 이정표에서 유지보수자들이 다른 언어로 전환하기로 결정하는지도 궁금함
  * Rust는 **Rust로 자체 재작성**하기로 하면서 OCaml에서 벗어났음. 글에서도 프로젝트 전체를 재작성하기에 흔한 시점으로 이를 암시했으며, 그 판단에 동의함
  * Roc의 핵심 목표 중 하나는 **컴파일러 속도**임. OCaml은 시스템 프로그래밍 언어가 아니어서 후보에서 제외된 것으로 추정함

* Zig의 **증분 빌드**는 분명 결정적인 기능이며, 단기적으로 이를 얻기 위해 언어를 바꾸는 선택은 이해됨  
  하지만 중기적으로 Rust에도 가까운 미래에 비슷한 기능이 추가되지 않을까 기대함  
  속도는 원하지만 빠르게 가다가 발등을 찍고 싶지는 않으며, Rust의 안전성, Zig의 기능, 가비지 컬렉션 없는 Go 런타임을 결합한 언어를 직접 만들고 있음
  * 빠른 Rust 빌드는 이미 [https://rust-lang.github.io/rust-project-goals/2026/roadmap-...](<https://rust-lang.github.io/rust-project-goals/2026/roadmap-fast-builds.html>)에서 작업 중이며, 이 페이지의 목표 대부분이 올해를 대상으로 함
  * Zig가 더 안전해지기 훨씬 전에 **Rust 컴파일 시간**이 빨라질 가능성이 큼
  * Rust 컴파일러가 빨라지기를 기다리기보다 Zig에 일종의 **빌림 검사기**를 추가하는 방향은 어떨지 궁금함  
    이쪽이 더 실현 가능성이 높고, 사용자 공간에서 구현하는 것도 가능해 보임
  * 가비지 컬렉션을 제외하면 **Go 런타임**의 특별한 장점이 무엇인지 궁금함
  * Rust의 안전성과 Zig의 기능을 결합하려고 남는 Codex 토큰을 가끔 [https://github.com/ityonemo/clr](<https://github.com/ityonemo/clr>)에 사용하고 있음

* 컴파일러 구현 언어를 고르는 과정에서 실제 **과학적 비교**를 했다면 훨씬 설득력 있었을 것임  
  고성능 컴파일러에는 저수준 시스템 언어가 필요하다는 검증되지 않은 가정([https://www.roc-lang.org/faq#self-hosted-compiler](<https://www.roc-lang.org/faq#self-hosted-compiler>))에서 출발해 Rust 외의 유일한 선택지가 Zig라고 결론 내린 듯함  
  컴파일러 성능은 알고리즘이 지배하며, 빠른 관리형 언어도 같은 알고리즘이라면 대체로 실행 시간이 두 배 이내인 반면 알고리즘 차이로 인한 성능 격차에는 한계가 없음  
  Zig 자체가 저수준 언어로 컴파일러를 작성하면 빨라진다는 이론의 반례이며, Roc의 초당 약 **1만 5천 줄**은 빠르지 않음. 1998년에도 ML 컴파일러가 초당 3천 줄을 처리했다는 자료가 있음([https://flint.cs.yale.edu/cs421/case-for-ml.html](<https://flint.cs.yale.edu/cs421/case-for-ml.html>))  
  현재 컴파일러 작업을 멈추고 1만 줄 미만으로 가능한 작은 Roc 부분집합의 **자체 호스팅 컴파일러**를 만드는 편이 미래에 더 도움 될 수 있음  
  그러면 30만 줄짜리 구현 대신 1만 줄 규모에서 여러 구현을 시험하고, 저수준 언어가 실제 성능 목표에 필요한지 검증할 수 있음  
  자체 호스팅 과정에서는 실제로 중요한 Roc 기능이 드러나며 Roc 코드도 더 많이 작성하게 되고, 컴파일러에 필요한 범용 기능을 개선하면 하위 애플리케이션도 함께 좋아짐
  * 과학을 요구하기에는 이 평가 역시 단정적이며 실증적 근거가 많지 않음  
    1990년대에 ML을 빠르게 컴파일했다는 사실만으로 오늘날 Roc의 컴파일 속도를 판단하기 어려움. 언어 설계가 필요한 알고리즘에 강한 제약을 주고, 현대 하드웨어도 훨씬 복잡하기 때문임  
    Roc에는 어느 정도의 오버로딩이 있고 힙에 클로저를 할당하지 않기 위한 정교한 알고리즘도 있는 듯하며, 이런 요구가 없앨 수 없는 알고리즘 복잡도를 만들 수 있음  
    알고리즘 최적화 한계에 도달하면 남는 것은 **상수 계수 절감**이며, 특히 메모리를 관리하는 고수준 언어는 이를 얼마나 낮출 수 있는지에 분명한 하한을 만듦  
    실제 코드에서 메모리 배치를 직접 제어해 성능이 10배 넘게 개선된 경우를 봤고, 게임 업계에서는 이런 작업이 경력의 큰 부분을 차지하기도 함. 영리한 알고리즘 하나로 모든 성능 문제가 사라지는 환경은 현실과 거리가 있음

* Rust 빌드는 모든 컴퓨터에서 저장 공간을 크게 낭비하는 원인 중 하나이며, 여러 라이브러리를 빌드하면 수십 GB가 금방 쌓임  
  의존성을 프로젝트 간 재사용하도록 **전역 빌드 폴더**를 설정할 수 있지만, 어떤 해법이든 기본 동작으로 제공하는 편이 바람직함
  * 더 빠른 빌드를 위해 **디스크 공간과 맞바꾸는 구조**이며, 경우에 따라 공간을 더 쓰면 속도를 더 높일 수도 있음  
    다만 캐시 가비지 수집은 필요하며, 이를 쉽게 만들 새로운 중간 빌드 산출물 배치 작업이 마무리 단계에 있음
  * JavaScript 생태계에서 `node_modules` 크기가 늘 비판받는 것을 생각하면 재미있는 대비임  
    프런트엔드보다 백엔드 코드가 훨씬 작은 Tauri 프로젝트에서도 **Rust 빌드 산출물은 9GB**이고, `node_modules`는 550MB에 불과함

* Roc을 C ABI에 삽입하는 스크립팅 언어로 이해하고 있는데, 실제 **활용 분야**가 궁금함  
  큰 Roc 플랫폼을 제공하는 플러그인 환경에서 WASM과 경쟁하려는지, 플러그인 개발자가 어떤 언어든 사용할 수 있는 WASM 대신 애플리케이션 개발자가 Roc 계층을 노출할 이유가 무엇인지 알고 싶음  
  작은 Roc 플랫폼을 사용하는 애플리케이션 수준 언어라면 서버 측 HTTP 코드에서 Gleam, 클라이언트 코드에서 Elm과 경쟁하려는지도 궁금함
  * 특히 함수형 언어처럼 처음 보는 언어가 어떤 애플리케이션에 쓰이는지 알아보는 것을 좋아하지만, **roc-lang.org와 FAQ**를 읽고도 Roc의 구체적인 활용처를 파악하지 못했음

* **컴파일 시간**은 심하게 저평가되는 요소임. C++ 빌드를 10분씩 기다리는 것이 가장 큰 불만이며 개발 몰입을 완전히 끊어 놓음
  * VS Code에서 구문 분석과 자동 완성을 위해 Rust-Analyzer를 쓰는데, 파일을 저장할 때마다 정보를 갱신하려고 컴파일러를 실행해 지나치게 느림  
    `.rs` 파일에서 `.ts` 파일로 바꾸면 컴퓨터 자체를 교체한 듯한 차이가 느껴질 정도임

* Zig를 직접 사용하지는 않지만 몇 가지 가능성에는 기대가 큼  
  C보다 사용하기 편한 Zig로 작성된 **새로운 게임**, TigerBeetle에서 이미 가능성을 보여준 **분산 소프트웨어**, 개인적으로 관심 있는 로보틱스 분야가 특히 기대됨
