zig에서 가장 흥미롭게 느끼는 부분은 빌드 시스템의 간편함, 크로스 컴파일, 그리고 높은 반복 속도 추구임. 나는 게임 개발자이기 때문에 성능이 중요하지만 대부분의 요구사항에 대해서는 대부분의 언어들이 충분한 성능을 제공함. 그래서 언어 선택의 최우선 기준은 아님. 어떤 언어로든 강력한 코드를 쓸 수 있지만, 수십 년 동안 유지보수할 수 있는 미래지향적인 프레임워크를 목표로 함. C/C++가 어디서나 지원되는 점에서 기본 선택지가 되었지만 zig도 그만큼 따라올 수 있을 것으로 느낌
재미로 아주 오래된 Kindle 기기(Linux 4.1.15)에 zig를 돌려봤는데 zig의 완성도에 놀라운 경험을 함. 대부분이 바로 작동했고, 오래된 GDB로도 이상한 버그를 디버깅할 수 있었음. 나도 zig에 매료됨. 자세한 경험은 여기에서 확인 가능
대부분의 언어로 강력한 코드를 쓸 수 있다고 느끼지만, 수십 년을 내다볼 수 있는 모듈러 코드를 원함. Zig를 좋아하지만, 장기 유지보수와 모듈성 측면에서는 단점이 있다고 생각함. Zig는 캡슐화에 적대적인 언어임. 구조체 멤버의 private 처리가 불가능함. 이 이슈 코멘트가 예시임. Zig의 입장은 내부 표현이란 게 따로 존재하지 않아야 하며 모든 사용자가 내부 구현을 알 수 있게 문서화/공개해야 한다는 것임. 하지만 API 계약, 즉 모듈러 소프트웨어의 핵심을 지키려면 내부 구현을 감출 수 있어야 하고, 그것이 불가능함. 언젠가는 Zig가 private 필드를 지원해 주길 바람
Rust를 가볍게 사용해봤는데 마음에 들었음. 하지만 '나쁘다'는 얘기를 듣고 한동안 멈췄다가 다시 써보는 중임. 여전히 좋음. 사람들이 왜 그렇게 싫어하는지 잘 모르겠음. 못생긴 제네릭 문법은 C#과 Typescript도 마찬가지임. 빌림 검사기(Borrow Checker)도 저수준 언어 경험이 있으면 이해하기 쉬움
Zig는 더 단순한 Rust, 그리고 더 나은 Go같은 느낌임. 한편 zig 위에 만들어진 도구 중에서 'bun'을 정말 감탄할 정도로 좋아함. bun 덕분에 삶이 엄청 간편해짐. Rust 기반의 'uv'도 비슷한 경험을 줌
C/C++가 기본이라는 점에 동의함. C보다 더 나은 무언가를 만들려고 해봐야 대부분 결국 C++이 되고 말았음. 그래도 시도는 멈추지 않아야 함. Rust와 Zig가 아직도 더 나은것을 기대하게 만드는 증거임. 난 지금부터 C++를 더 배워볼 예정임
최첨단 컴파일러들이 언어 스펙을 깨뜨릴 때가 있다고 해도, Clang의 무한루프 종료 가정은 C11 이후 표준에 따르면 맞는 것임. C11에서는 다음과 같이 명시됨. "제어식이 상수 표현이 아니고, 입출력/volatile/sync/atomic 연산도 하지 않는 반복문은 컴파일러가 종료된다고 가정할 수 있음"
C++에서는(향후 C++26 전까지) 모든 루프에 해당 규정이 적용되지만, 말씀하신 대로 C 언어에서는 "제어식이 상수 표현이 아닌 반복문"에만 해당됨. 즉, for(;;); 같은 명백한 무한 반복문은 실제로도 무한루프가 되어야 하고, Rust의 loop {} 역시 같아야 함. 그런데 LLVM 개발자들이 종종 자신들이 C++ 컴파일러만 만든다고 착각해서, Rust에서는 "무한루프 부탁드립니다" 해도 LLVM이 "C++ 기준으로는 그런 일 없으니 최적화!"를 적용시켜 문제 발생. 잘못된 언어에 잘못된 최적화가 적용된 셈임
컴파일타임(comptime) 기능이 없어서 문자열 비교를 인라인, 언롤하는 것은 C에서도 충분히 가능함. 관련 예시
지적이 맞음! 처음 예시는 너무 단순했음. 더 좋은 예시는 컴파일타임 서픽스 오토마톤이 있음. 또, 위에 링크한 godbolt 코드는 오히려 하지 말아야 할 두 가지 사례 중 하나를 보여주고 있음
예시로 든 JavaScript 코드가 V8에서 생성된 바이트코드가 비효율적이라고 한 부분은 좋은 비교 예시가 아니라고 생각함. Zig와 Rust에는 아주 최신 환경을 지정해서 컴파일하라고 하면서, V8은 그런 최적화 옵션을 강제하지 않음. 사실 현대 JIT들도 상황만 허락한다면 벡터화 가능함. 그리고 대부분 현대 언어들도 문자열 관련한 최적화는 비슷하게 처리함. 참고로 C++의 예시도 있음
사실상 JS와 Zig를 비교하는 건 사과와 과일 샐러드를 비교하는 격임. Zig 예시는 타입과 크기가 고정된 배열을 썼는데, JS는 런타임에 다양한 타입이 들어가는 'generic' 코드임. 이 때문에 JS에서는 타입 정보 제공만 잘하면 JIT이 훨씬 빠른 루프를 만들어냄(비록 벡터화까진 아니더라도). 실제론 TypedArray를 자주 쓰진 않는데, 초기화 비용이 크기 때문이고, 재사용이 잦을 때만 쓸만함. 또 글에서는 JS 코드가 부풀려졌다고 했지만, JIT이 어레이 길이 체크를 못 믿어서 가드를 넣는 경우가 크고, 실제로는 누구나 i < x.length 같은 루프를 써서 JIT 최적화가 됨. 그런 점에서 조금은 트집이지만, 미세한 차이이긴 함
Rust와 Zig의 godbolt 예제를 더 오래된 CPU로 타겟 변경도 가능함. JS 쪽 타겟 제한은 생각을 못했음. 그리고 C++의 예시는 clang이 얼마나 좋은 코드를 내는지 보여주는 사례임. 다만 현조차로는 assembly가 썩 만족스럽지는 않음(zig가 특정 CPU 타겟으로 빌드되는 걸 감안해도). 컴파일타임 Suffix Automaton의 C++ 포팅 예시도 있다면 정말 흥미로울 듯. 이건 C++ 컴파일러가 추측 불가능한 comptime의 실제 활용 사례임
"하이레벨 언어는 저수준 언어가 갖고 있는 'intent'가 부족하다"는 말에 의문임. 오히려 더 다양한 방식으로 상세하게 의도를 표현하는 게 하이레벨 언어의 장점이라고 봄
나도 동의함. 근본적으로 하이레벨 언어와 로우레벨 언어의 차이는, 하이레벨 언어에선 의도를 표현하고 로우레벨에선 구현 메커니즘 그 자체를 드러내야 한다는 차이임
여기서 '의도'란 "이 구매의 세금 계산"같은 업무적 의도가 아니라, "이 바이트를 왼쪽으로 세 칸 쉬프트"하는 식의, 컴퓨터에 무엇을 시키는가에 가까움. 예를 들어 purchase.calculate_tax().await.map_err(|e| TaxCalculationError { source: e })?; 같은 코드는 의도가 가득하지만, 실제로 머신 코드가 어떻게 나올지는 예측이 불가임
Zig의 allocator 모델이 정말 마음에 듦. Go에서 GC 대신 요청별 allocator 같은 것을 쓸 수 있으면 좋겠음
Go에서도 커스텀 allocator와 arena가 불가능하지는 않으나, 사용성이 매우 떨어지고 적절히 쓰기 힘듦. 언어 차원에서 소유권(ownership) 규칙을 표현하거나 강제할 방법도 없음. 결국 문법만 살짝 다른 C를 쓰는 꼴이고, GC 없으면 C++보다도 위험한 셈임
"Zig의 장황함(verbosity)이 마음에 든다"는 말은 공감하지만, 솔직히 조금 어감이 이상함. C는 여기저기 허술한 반면, Zig는 반대로 너무 많은 '주석 소음(annotation noise)'를 요구하는 경우가 많은 편임(특히 수학식에서 명시적 정수 캐스팅 시). 관련 글 참고. 성능 측면에선 zig가 c보다 빠른 경우는 주로 Zig가 더 공격적인 LLVM 최적화 세팅(-march=native, 전체 프로그램 최적화 등) 때문임. 사실 C에서도 unreachable 같은 최적화 힌트는 언어 확장으로 가능하고, Clang도 상수 폴딩에 매우 적극적임. 즉, Zig의 comptime과 C의 코드젠 차이는 컴파일러 최적화 세팅에서 비롯된 경우가 많음. TL;DR: C가 느릴 땐 컴파일러 설정을 먼저 점검해야 함. 어차피 최적화의 핵심은 LLVM임
캐스팅 부분 예시라면, 오히려 함수를 하나 만들어서 캐스팅을 감싸는 식으로 코드 재활용성과 의도를 높여줄 수 있음
Zig의 아이디어들이 흥미롭고, 원래 기사에서 기대했던 것보단 컴파일타임(comptime)과 전체 프로그램 컴파일에 더 무게가 실려 있었음. 이에 공감함. 참고로 Virgil은 2006년부터 컴파일타임 전체 언어 활용, 전체 프로그램 컴파일 지원을 했음. Virgil은 LLVM 타겟팅은 아니므로 속도 비교는 결국 백엔드 비교임. Virgil은 이 접근법 덕에 메서드 호출을 미리 정적으로 결합(devirtualize), 안 쓰는 필드/객체도 최대한 제거, 필드-힙 객체까지 상수 전파, 완벽하게 특수화 등 매우 강한 최적화가 가능함
향후 AI 활용을 생각하면, 점점 더 명시적이고 장황한 언어들이 대세가 될 것 같음. AI로 코딩을 하냐, 그게 옳으냐를 떠나 많은 개발자들이 AI의 도움을 선호하게 되면서 언어들도 그에 맞춰 변할 것임
새 x86 백엔드가 도입된다면, 앞으로는 C와 Zig의 성능 차이가 Zig 프로젝트 자체에 기인하는 사례도 볼 수 있을 것 같음
명시적 integer 캐스팅 관련해서, 곧 좀 더 깔끔해지는 개선이 나올 예정임. 관련 논의 참고
"C가 Python보다 빠르다" 같이 언어 그 자체로 벤치마킹하는 건 맞지 않지만, 언어의 일부 기능이 최적화에 큰 장벽이 되기도 함. 적절한 언어를 쓰면, 개발자와 컴파일러 모두 자연스럽고 빠른 방식으로 의도를 표현 가능함
Zig의 for loop 문법이 너무 난잡하게 느껴짐. 리스트 두 개를 나란히 놓고 위치를 맞춰야 한다니, 보기만 해도 눈이 아픔. 근래 언어들이 너무 많은 '매직' 문법과 특수 기호를 쏟아붓는 게 실수라고 봄. 몇 시간 동안 들여다보고 있기 힘들 것 같음
이런 배열 두 개를 순회하는 패턴은 저수준 코드에서 매우 흔하고, 병렬로 순회하는 것도 마찬가지임. 그래서 Zig가 이를 명확하고 자연스럽게 지원하는 게 오히려 적절하다고 봄. 왜 그게 눈이 아플까 궁금함
Hacker News 의견