타입 해석 재설계와 언어 변경 사항
(ziglang.org)- Zig 컴파일러의 타입 해석(type resolution) 로직이 전면 재설계되어, 내부 구조가 단순화되고 사용자에게도 가시적인 개선이 이루어짐
- 새 설계는 타입 필드 분석을 지연(lazy) 처리해, 초기화되지 않은 타입의 세부 구조를 불필요하게 검사하지 않음
- 의존성 루프(dependency loop) 오류 메시지가 구체적으로 개선되어, 루프의 원인을 명확히 파악할 수 있게 됨
- 증분 컴파일(incremental compilation) 기능의 과도한 분석 문제와 다수의 버그가 해결되어, 빌드 속도가 크게 향상됨
- 이번 변경은 수십 개의 버그 수정과 소규모 언어 개선을 포함하며, Zig 컴파일러의 성능과 개발 경험을 전반적으로 강화함
타입 해석 로직의 재설계
- 약 3만 줄 규모의 PR이 병합되어, Zig 컴파일러의 타입 해석 로직이 더 논리적이고 직관적인 구조로 재작성됨
- 이 과정에서 컴파일러 내부 구조가 정리되었으며, 사용자에게도 직접적인 개선 효과가 있음
- 컴파일러가 타입 필드 분석을 지연 평가하도록 변경되어, 초기화되지 않은 타입의 세부 구조를 불필요하게 탐색하지 않음
- 예시 코드에서
@compileError필드를 포함한 구조체가 네임스페이스로만 사용될 경우, 이전에는 컴파일 오류가 발생했으나 이제는 정상적으로 컴파일됨 - 이는
std.Io.Writer와 같은 네임스페이스형 타입 사용 시 불필요한 코드 종속을 방지함
- 예시 코드에서
의존성 루프 오류 메시지 개선
- 이전에는 의존성 루프 오류 메시지가 모호했으나, 이제 루프의 원인과 위치를 명확히 표시함
- 예시 코드에서
Foo와Bar구조체가 서로를 참조할 때, 오류 메시지가 각 타입의 의존 위치를 구체적으로 지적함 - 메시지에는 루프 길이, 각 필드 선언 위치, 정렬 쿼리 위치 등이 포함되어 있음
- 예시 코드에서
- 복잡한 루프에서도 충분한 정보를 제공해, 문제 원인을 쉽게 파악할 수 있음
증분 컴파일 성능 향상
- 이번 변경으로 증분 컴파일 기능의 다수 버그가 수정됨
- 특히 “과도한 분석(over-analysis)” 문제를 해결해, 변경된 부분만 재컴파일하도록 최적화됨
- 결과적으로 많은 경우에서 컴파일 속도가 크게 향상됨
- 개발자는 Zig 0.15.1 이상 버전에서 증분 컴파일을 활성화해 개선된 개발 경험을 체험할 수 있음
기타 개선 사항
- 이번 PR에는 수십 개의 버그 수정과 소규모 언어 변경, 컴파일러 성능 개선이 포함됨
- 대부분은 세부적이거나 특수한 사례에 해당함
- 전체 변경 내역은 Codeberg의 PR #31403에서 확인 가능
- 새로운 버그 발견 시 이슈 보고를 권장함
변경의 의의
- 타입 해석 로직의 단순화와 증분 컴파일 최적화로 Zig 컴파일러의 안정성과 효율성이 강화됨
- 개발자는 더 빠르고 명확한 피드백을 받으며, 대규모 코드베이스에서도 생산성 향상을 기대할 수 있음
Hacker News 의견들
-
나는 이 devlog의 작성자임
언어 변경으로 인한 호환성 깨짐에 대한 우려는 이해하지만, 이번 컴파일러 변경이 큰 파급을 일으키는 수준은 아님을 밝히고 싶음
예를 들어 ZLS를 새 브랜치로 빌드할 때,.{}를.empty로 바꾸는 정도의 수정만 필요했음. 이는std.ArrayList의 기본값 제거 때문이며, 이미 1년 전부터 deprecated 상태였음
또 Awebo 프로젝트의 경우도 전체 의존성 트리에서 수정해야 할 부분은 세 가지뿐이었음 —.empty변경,comptime추가,orelse @alignOf(T)추가
이런 수정은 대부분 Zig 개발자라면 자동 반사적으로 처리할 수준의 단순한 변경임
이번 PR의 핵심은 깨짐보다는 버그 수정과 증분 컴파일 개선에 있음- 나는 변경에 비판적으로 보였던 댓글 작성자 중 한 명임
PR의 품질과 계획성은 매우 높다고 생각하며, 작성자의 노력을 폄하하려는 의도는 전혀 없었음
다만 앞으로는 더 많은 주석을 달고 신중히 의견을 남겨야겠다는 교훈을 얻었음 - Zig에 직접 관여하지는 않지만,
lib/std/multi_array_list.zig에 추가된 주석을 보고 궁금한 점이 생겼음
@alignOf(T)를MultiArrayList(T)정의에 사용하면 왜 순환 의존성이 생기는지 이해가 안 됨
T가MultiArrayList자체라 해도 완전히 별개의 모노모픽 타입 아닌가? 내가 뭔가 놓친 게 있는 듯함
관련 코드: 링크
- 나는 변경에 비판적으로 보였던 댓글 작성자 중 한 명임
-
Zig를 프로덕션 환경에서 사용하는 사람들의 경험이 궁금함
언어가 자주 바뀌는데, 업데이트 주기나 리라이트 주기는 어떤지, 의존 패키지가 언어 버전에 뒤처지는 경우가 있는지도 알고 싶음
Bun이 Zig를 잘 활용하고 있는 건 알지만, 다른 사례도 듣고 싶음- 나는 약 25만 LoC 규모의 Zig 컴파일러 코드베이스를 유지 중임 (roc-lang/roc)
지난 1~2년간 언어와 표준 라이브러리의 변경은 큰 문제 없이 진행되어 왔음
예전에는 업그레이드가 번거로웠지만, 지금은 “약간의 불편함” 정도로 느껴짐
Zig 사용 경험을 묻는다면, 이 부분은 거의 언급조차 안 할 정도로 안정적임 - 나는 tigerbeetle과 sig 두 개의 프로덕션 Zig 코드베이스에서 일했음
이런 대형 프로젝트들은 태그된 릴리스를 기준으로 업그레이드하며, 보통 며칠~몇 주 내에 마이그레이션을 완료함
의존성도 거의 없어서 업그레이드 부담이 크지 않음 - Zig 0.15는 꽤 안정적임
다만 사소한 오타로 SIGBUS 컴파일러 크래시가 나는 경우가 있어 디버깅이 힘듦
.zig-cache가 173GB까지 커져서 ARM VPS에서는 문제를 일으키기도 함
lightpanda를 0.14→0.15로 올릴 때는 무난했음. 0.16도 큰 문제는 없을 듯
하지만 라이브러리 개발자로서는 0.16의 빠른 변화 속도를 따라가기 힘듦
현재는 “dev” 브랜치에서만 실험적으로 대응 중임 - 약 2만 LoC 규모의 Zig 0.16 코드를 DebugSafe 모드로 프로덕션에서 돌리고 있음
Node.js/TypeScript 모듈을 Zig로 리라이트했는데, 2배 빠르고 메모리 사용량은 70% 감소했음
Zig의sqlite/JSON직렬화 지원이 강력해서 큰 장점이었음
단점은 클로저나 vtable 문법 부재로 코드 계층 분리가 어려운 점임
Arcs와 범퍼 할당자를 써서 메모리 안전성은 확보했고, DebugSafe 모드로 계속 운영할 계획임
ReleaseFast로 전환 시 25% 속도 향상은 있었지만, 안전성을 잃을 만큼의 이득은 아님 - C++의 영원한 하위 호환성 약속은 오히려 언어 발전을 막은 실수였다고 생각함
코드를 수정해야 하더라도 장기적으로는 올바른 접근임
- 나는 약 25만 LoC 규모의 Zig 컴파일러 코드베이스를 유지 중임 (roc-lang/roc)
-
Zig 팀의 성과에 감명받았음
나는 Zig로 만든 ghostty 터미널을 자주 쓰는데, 매우 안정적임
다만 개인적으로는 Rust를 선호함
Rust는 “닫힌 세계” 모델, Zig는 “열린 세계” 모델을 택함
Rust는 trait을 명시적으로 구현해야 하지만, Zig는 타입의 형태(shape) 가 맞으면 동작함
이 덕분에 Zig는 강력한 메타프로그래밍이 가능하지만, 타입 추론이 불명확해 자동완성·문서화·LSP 지원이 어렵다는 단점이 있음- 구체적인 예시가 궁금함
설명을 들으니 Go의 인터페이스와 비슷하게 들리는데, Zig에는 직접적인 대응 개념이 없는 것으로 알고 있음
- 구체적인 예시가 궁금함
-
kernel32에서Ntdll로의 전환이 흥미로웠음
이는 Linux 사용자 공간 API에도 적용 가능한 개념임
특히 커널-유저 경계에서의 오류 처리 방식이 유사함
다만 Linux에서는 libc와 커널이 밀접하게 얽혀 있어서errno사용이 필수적임
Windows에서도 이런 패턴이 생긴 이유가 궁금함-
errno나GetLastError()패턴은 스레드 이전 시대의 유산임
과거에는 협력적 스케줄링이라 전역 변수가 안전했지만, 멀티코어와 스레드가 등장하면서 위험해졌음
그래서 thread local이 그 대안으로 등장했음
-
-
타입을 네임스페이스처럼 쓰는 대신, 언어에 명시적 네임스페이스를 추가하는 게 낫지 않을까 생각함
- Zig는 언어 최소주의를 지향함
여러 곳에서 최적화되는 기능이라면 그때 추가하는 접근을 택함 - 사실 이는 우회가 아니라 디자인의 우아함임
Zig에서@import는 파일을 구조체로 변환하고, 네임스페이스는 단순히 중첩된 struct로 표현됨
즉, 네임스페이스는 또 다른 import에 불과함
(커피가 아직 덜 들어서 정확도는 장담 못 함)
- Zig는 언어 최소주의를 지향함
-
언어 변경 논의에서 종종 간과되는 부분이 있음 — 바로 생태계 영향임
언어가 자주 깨지면 앱뿐 아니라 라이브러리·도구·튜토리얼 등도 계속 쫓아가야 함
결과적으로 “한 번 만들고 방치되는” 라이브러리보다는 활발히 유지되는 프로젝트 중심으로 생태계가 기울게 됨
이는 초기 언어 설계 단계에서는 타당한 트레이드오프지만, 장기적으로는 생태계 성장에 영향을 줌
다른 신생 언어들은 이런 변화 피로도 최소화에 많은 노력을 들이고 있음
Zig의 접근이 어떤 결과를 낳을지 지켜보는 것도 흥미로움- 예로 Blender 애드온 생태계를 들 수 있음
Blender는 자주 API를 깨뜨리지만, 대부분의 수정은 사소함
다만 누군가는 그걸 고쳐야 하고, 유지보수가 끊기면 사용자가 직접 패치해야 함
유료 애드온은 유지될 가능성이 높지만, 그것도 보장은 아님 - 나는 그래도 Zig가 그럴 가치가 있다고 생각함
유지보수 안 되는 라이브러리는 어차피 나쁜 코드임
Zig를 비판하는 대신, 다른 언어(C3 등)를 홍보하는 건 그만두길 바람
- 예로 Blender 애드온 생태계를 들 수 있음
-
Zig의 PR에서 언급된 “Chromium, boringssl, Firefox, Rust가 advapi32.dll의 SystemFunction036을 호출한다”는 내용은 사실이 아님
이들은 이미 ProcessPrng를 사용 중이며, Windows 10 이후에는 실패하지 않음
관련 근거는 Microsoft whitepaper에 있음
RNG 요청이 절대 실패하지 않도록 설계되어 있으며, 실패 시 프로세스 자체가 종료되도록 되어 있음
즉, 고품질 난수 보장을 위해 오류 코드를 반환하지 않음- (이건 같은 페이지의 다른 devlog에 대한 답글임)
-
Zig의 언어 의미론은 표면적으로 단순하지만, 상호작용이 미묘함
이런 점이 C++ 템플릿 규칙처럼 시간이 지나며 복잡한 모서리 케이스를 낳을 수도 있을 것 같음 -
3만 줄짜리 PR은 대단한 성취임
하지만 언어 의미론을 바꾸는 건 매우 중대한 일이라 놀랐음
Zig는 아직 1.0 전이라 변화가 빠르다는 건 이해하지만, “이 브랜치에서 의미론을 바꿨다”는 식의 캐주얼한 표현이 다소 당황스러웠음
이런 대규모 변경이 Zig 특유의 문화인지, 아니면 내가 시대에 뒤처진 건지 궁금함
“modern Zig”라는 표현도 언어의 빠른 변화 속도 때문에 웃음이 나왔음- 문체가 캐주얼하다고 해서 가벼운 태도로 봐서는 안 됨
devlog는 마케팅 글이 아니라 내부자용 기록에 가깝고, Zig는 아직 1.0이 아님
PR에는 충분한 맥락과 근거가 담겨 있음
Zig를 선택한 시점에서 일정 수준의 언어 변화 리스크는 감수한 셈임
오히려 지금 시점에 깨끗하게 다듬는 게 장기적으로는 이득임
(C의 비트 연산자 우선순위처럼 고칠 수 없는 유산을 떠올려보면 됨) -
mlugg는 Zig 핵심 기여자이자 Zig Foundation 멤버임
이번 변경은 순환 의존성 해소와 타입 시스템 정리를 위한 작업임
관련 제안은 #3257과 #15909에 공개되어 있음
이 변경으로 Zig의 타입 해석이 DAG(유향 비순환 그래프) 구조로 정리되어, 컴파일러 안정성이 크게 향상됨
Zig는 BDFN(Benevolent Dictator For Now) 모델로 운영되며, 최종 결정권은 Andrew Kelley에게 있음
하지만 팀은 비영리 조직으로, 사용자 신뢰와 언어 품질을 최우선으로 함
개인적으로 Matthew와 함께 일하는 건 큰 영광임 - 아마 이런 태도가 C 언어의 혼란스러운 역사를 반면교사로 삼은 결과일 수도 있음
형식적으로는 완벽했지만, 실제로는 혼돈의 언어였던 C를 떠올리게 함
- 문체가 캐주얼하다고 해서 가벼운 태도로 봐서는 안 됨