2026년의 Zig vs Rust

48 minutes ago 2
  • Zig의 unsafe 코드 인체공학은 여전히 강점이지만, 코딩 에이전트가 코드를 많이 대신 쓰면서 체감 가치가 줄어듦
  • Zig의 할당자 인터페이스는 arena·stack fallback 같은 특화 할당자를 쉽게 쓰게 해주지만, Rust도 nightly Allocator trait로 격차를 좁힘
  • Zig의 임의 비트 폭 정수와 packed struct는 tagged pointer 같은 비트 레이아웃 표현에 강하지만, 에이전트가 Rust의 마스크 코드 작성 부담을 낮춤
  • Zig의 comptime은 강력하지만 주 사용처 대부분은 제네릭 데이터 구조였고, Rust의 타입 시스템이 더 많은 불변 조건을 강제함
  • 코딩 에이전트가 코드량을 크게 늘리는 환경에서는 메모리 검토 부담도 커져, borrow checker와 miri를 갖춘 Rust가 더 선호됨

핵심 변화

  • Zig는 unsafe 코드의 인체공학에서 큰 장점이 있었지만, 사람이 직접 코드를 쓰는 비중이 줄면서 그 장점의 실사용 가치도 작아짐
  • Zig 기능이 주는 1.5~5배 수준의 인간 개발자 생산성 향상Rust에서 코딩 에이전트를 쓰는 100배 향상에 가려짐
  • Zig의 대표 기능 상당수는 사람이 손으로 코드를 작성할 때의 편의성을 높이지만, 코딩 에이전트에는 그 차이가 크게 중요하지 않음
  • 약 3년 전에는 Zig와 unsafe Rust로 바이트코드 VM과 가비지 컬렉터를 작성하면서 unsafe 코드 작성 경험은 Zig 쪽이 낫다고 느꼈음
  • 2026년 기준으로도 Zig는 좋은 언어지만, Rust가 더 선호되고 코딩 에이전트와도 더 잘 맞는 언어로 바뀜

Zig의 할당자 인터페이스

  • Zig의 할당자 인터페이스는 특정 코드 경로를 최적화하기 위해 arena, stack fallback 같은 특화 할당자를 쉽게 적용하게 해줌
  • 사용자 입력 한 줄을 읽는 경우 입력 길이는 이론상 무제한이어서 힙 할당자가 필요하지만, 실제 입력은 대부분 짧은 검색어나 경로라 1KB보다 훨씬 작음
  • std.heap.stackFallback(256, heap_allocator)는 고정 크기 버퍼를 스택에 두고, 입력이 넘칠 때만 힙으로 넘어가게 해 일반적인 경우 힙 할당 없이 처리 가능함
  • 과거 Rust에는 Zig의 Allocator 인터페이스에 해당하는 기능이 없어, 커스텀 할당자를 쓰는 Vec<T>가 필요하면 표준 라이브러리 구현을 복사해 수정해야 했음
  • Bumpalo의 컬렉션 소스는 표준 컬렉션을 fork해 bump allocator에 연결한 형태였음
  • Rust nightly에는 한동안 Allocator trait가 있었고, 지금은 충분히 좋아 보이는 수준이 됨
  • Rust의 Allocator는 trait 기반이라 정적 디스패치를 쓰고, Zig의 할당자는 vtable 기반이라는 차이가 있음
  • Zig처럼 데이터 구조를 할당자 매개변수 기반으로 설계하는 커뮤니티 전반의 관례는 Rust에 없지만, AI가 코드를 복사해 바꾸기 쉬워지면서 이 한계가 덜 중요해짐

임의 비트 폭 정수와 packed struct

  • Zig의 임의 비트 폭 정수와 packed struct는 데이터 지향 설계식 CPU 캐시 최적화, tagged pointer, NaN boxing, bitflags 같은 작업을 쉽게 만들어줌
  • Obj-C API를 Metal과 함께 Objective-C runtime C API로 사용할 때, id는 정렬된 힙 객체 포인터가 아니라 tagged pointer일 수 있음
  • 정렬을 가정한 코드에 tagged NSNumber를 넘기면 UB가 발생할 수 있어, “힙 포인터인지 tagged immediate인지”를 저렴하게 검사해야 함
  • 단순화한 Objective-C tagged pointer 배치는 낮은 1비트가 “힙 포인터가 아님”을 나타내고, 다음 3비트가 클래스 슬롯을 식별하며, 나머지 60비트가 payload가 됨
  • Zig는 enum(u3)와 packed struct로 class: TaggedClass, payload: u60처럼 비트 레이아웃을 타입으로 직접 표현할 수 있음
  • Zig에서는 @bitCast로 원시 u64와 ObjcTaggedPointer를 오가며, is_ns_number에서 is_tagged와 .ns_number 클래스를 검사할 수 있음
  • Rust 대응 코드는 ObjcTaggedPointer(u64) 안에서 TAG_MASK, CLASS_MASK, CLASS_SHIFT, PAYLOAD_SHIFT 같은 상수를 두고, 생성 시 OR 연산을 하고 접근 시 마스크를 적용함
  • Rust에서는 클래스 슬롯이 실제 타입이 아니라 u64 상수이며, 손으로 쓰는 방식은 Zig보다 덜 인체공학적
  • Rust에서는 bitfieldbitflags 같은 crate를 쓰는 편이 낫지만, 둘 다 proc macro에 의존하고 Zig의 packed struct만큼 좋게 느껴지지는 않음
  • 코딩 에이전트가 있으면 이런 코드를 손으로 쓰기 귀찮다는 문제가 크게 줄어듦

comptime의 가치 변화

  • Zig의 comptime은 가장 화려한 기능이며, 일부 난해한 의존 타입 언어를 제외하면 Zig만큼 좋은 컴파일 타임 평가를 제공하는 언어가 거의 없다고 볼 수 있음
  • 실제 사용에서는 comptime을 많이 그리워하지 않게 됐고, 사용량의 약 95%는 매개변수화된 타입의 제네릭 데이터 구조를 만드는 데 쓰였음
  • fn ArrayList(comptime T: type) type처럼 타입을 받아 items: []T, capacity: usize, allocator: Allocator를 가진 구조체 타입을 반환하는 패턴이 대표적임
  • Rust의 타입 시스템은 Zig식 comptime 제네릭의 상당 부분을 대체하며, 더 많은 불변 조건을 강제할 수 있음
  • 나머지 약 5%의 경우에는 comptime이 없어서 불편하고, 신뢰할 만한 대체 수단은 codegen뿐임
  • 게임 개발 중 도구에서 생성된 hitbox geometry 데이터를 하드코딩해 자료구조에 넣고 싶을 때, Rust에서는 Claude에게 Rust 파일을 생성하는 스크립트를 작성하게 해야 함
  • 그래도 컴파일 타임 평가가 실제로 자주 필요하지는 않음

Rust 타입 시스템의 장점

  • Rust의 타입 시스템은 Zig의 comptime보다 더 가치 있는 교환 대상으로 평가되며, 특히 bounded polymorphism을 위한 traits/typeclasses 영역에서 강함
  • Zig에서 같은 수준의 bounded polymorphism을 구현하려 하면 매우 어려움
  • Rust 타입 시스템은 더 많은 불변 조건(invariant) 을 강제할 수 있어, 코딩 에이전트가 흔히 저지르는 실수를 막는 데 도움이 됨
  • 게임 코드에서는 euclid crate를 사용해 그래픽 프로그래밍에서 흔한 문제인 좌표 공간 혼동을 방지함
  • Point<Screen> 또는 Point<World>처럼 각 좌표 공간에 특화된 타입을 만들면, 월드 좌표와 스크린 좌표를 실수로 섞는 일이 컴파일 단계에서 막힘
  • WorldPoint, WorldVector, ScreenPoint를 별도 타입으로 두면 같은 공간의 point와 vector 덧셈은 허용됨
  • Translation2D::<f32, WorldSpace, ScreenSpace>를 통해 월드 공간에서 스크린 공간으로 명시적으로 변환할 수 있음
  • 반대로 let bad: ScreenPoint = player;처럼 WorldPoint를 ScreenPoint에 바로 대입하는 코드는 허용되지 않음

메모리 문제를 덜 다루는 효과

  • 코딩 에이전트가 100배 더 많은 코드 작성을 가능하게 하면, Zig 코드에서 메모리 문제를 검토해야 하는 양도 100배 늘어남
  • 형식 검증이 없다면 버그를 찾기 위해 살펴봐야 하는 탐색 공간의 표면적이 훨씬 커짐
  • 현재처럼 생성되는 코드의 양이 커진 상황에서는 Rust가 더 매력적임
  • Rust의 전통적 절충점은 borrow checker에 익숙하지 않을 때 개발자 생산성을 저해한다는 것이었지만, 코딩 에이전트가 있으면 이 단점의 중요성이 크게 줄어듦
  • Rust에서 unsafe를 쓰더라도 miri 같은 도구를 코딩 에이전트가 실행하게 해 UB가 발생하지 않는지, Rust의 aliasing 규칙을 위반하지 않는지 확인할 수 있음

결론

  • Zig는 여전히 그리운 언어이고 좋은 언어임
  • 2026년의 작업 방식에서는 Rust가 더 선호되며, 코딩 에이전트와의 궁합도 Rust가 더 좋음
Read Entire Article