# Zig가 멋진 이유는 무엇일까?

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

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24228](https://news.hada.io/topic?id=24228)
- GeekNews Markdown: [https://news.hada.io/topic/24228.md](https://news.hada.io/topic/24228.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-11-08T18:33:15+09:00
- Updated: 2025-11-08T18:33:15+09:00
- Original source: [nilostolte.github.io](https://nilostolte.github.io/tech/articles/ZigCool.html)
- Points: 1
- Comments: 1

## Topic Body

- **C 코드 컴파일과 크로스 컴파일 기능을 기본 제공**하는 Zig 컴파일러는, 45년 경력의 저자가 경험한 언어 중 가장 놀라운 언어임  
- **컴파일 타임 실행, 임의 비트 크기 변수, 테스트 블록 환경** 등 독특한 기능으로 단순한 C/C++ 대체를 넘어 완전히 새로운 프로그래밍 방식 제공  
- **타입 추론을 통한 변수 선언, 익명 구조체, 레이블 브레이크** 등 간결하고 명확한 문법으로 빠른 학습 가능  
- **테스트 블록을 통한 독립적 모듈 테스트와 @breakpoint 내장 함수**로 최적화된 코드 디버깅 지원  
- **비트 필드와 비트 연산을 활용한 저수준 프로그래밍 지원**으로 효율성과 견고성을 동시에 달성하며, 인터프리터 언어의 장점을 컴파일 언어에 통합  
  
---  
### 서문  
- 45년 경력 중 Zig만큼 놀라운 언어는 없었음  
  - Zig는 단순한 새로운 언어가 아니라, **프로그래밍 방식을 근본적으로 바꾸는 도구**  
- C나 C++을 대체하는 수준으로만 보는 것은 **큰 과소평가**임  
- 이 글의 목적은 Zig의 **간단하면서도 매력적인 기능**을 소개하고, 프로그래머가 빠르게 시작할 수 있도록 돕는 것  
- 산업계에서 Zig의 수용성에 영향을 미치는 더 많은 기능이 존재함  
  
### Zig 컴파일러  
  
- **C 코드 컴파일과 크로스 컴파일 기능을 별도 설정 없이 기본 제공**하여 산업계에 큰 영향을 줌  
- 설치는 Zinglang 다운로드 페이지에서 프로세서/OS별 컴파일러를 다운로드 후 압축 해제하여 원하는 디렉토리에 복사  
  - Windows 10에서는 x86_64 zip 파일을 "Program Files"에 복사하고, 루트 디렉토리 이름을 "zig-windows-x86_64"로 변경하여 버전 업데이트 시 Path 환경 변수 수정 불필요  
  - Path 환경 변수에 루트 디렉토리 경로 추가 후 CLI 모드에서 컴파일러 사용 가능  
- "Hello World!" 프로그램 빌드는 공식 사이트의 "Getting Started" 섹션 참조 권장  
  
### 주요 개념과 명령  
  
#### 변수 선언  
  
- **변수 선언은 접근성(pub 또는 생략), var/const, 변수명으로 구성된 첫 번째 부분, 타입 선언인 두 번째 부분, 초기화인 세 번째 부분으로 구성**  
  - 첫 번째와 세 번째 부분만 필수이며, **타입은 초기화 값으로부터 추론 가능**  
  - 예: `var sum : usize = 0;`  
- `pub` 없이 선언된 변수는 모듈 내부에서만 접근 가능 (C의 static 변수와 유사)  
- **pub 변수 선언은 권장되지 않으며, pub 함수는 최소화하여 결합도를 낮추고 응집도를 높이는 것이 권장됨**  
  
#### 구조체, 익명 구조체, 테스트 블록  
  
- **`.{`와 `}`로 둘러싸인 익명 구조체 리터럴**은 다른 구조체 요소 초기화 또는 요소가 초기화된 새 구조체 생성에 사용  
- `.{ }`는 빈 익명 구조체 리터럴  
- `struct { }` 형태는 구조체 선언  
- **테스트 블록은 실행 파일 없이 컴파일 및 테스트 실행 가능**  
  
#### 비트 필드  
  
- **비트 필드는 packed struct에서 특정 크기의 타입을 가진 필드로 선언**  
- 포인터는 특정 비트 필드를 가리킬 수 있음  
  
#### For 루프  
  
- Zig 문법은 C보다 명확하나, `[0..8]`이 아닌 **열린 구간 `[0..9)` 사용**  
- **루프 변수 `i`의 타입 선언, 초기화, 테스트, 증가가 자동으로 처리됨**  
  
#### 배열  
  
- **`[_]`는 크기를 알 수 없는 배열을 정의**하며, 요소 타입과 초기화가 뒤따름  
  - 예: `var grid = [_]u8{0} ** 81;`는 81개의 u8 요소를 0으로 초기화  
  - **배열 크기는 초기화 반복 인자로부터 추론됨**  
- 테스트 환경에서 배열 요소를 순회하며 합산 가능  
- **for 루프의 `|` 사이에 선언된 변수는 배열 요소와 동일한 타입으로 자동 가정**  
- `usize`는 플랫폼의 자연 부호 없는 정수 (64비트에서 u64, 32비트에서 u32)  
  
#### 다항목 포인터  
  
- **배열 포인터가 포인터 산술 연산을 사용하려면 `[*]const i32`처럼 명시적으로 다항목 포인터로 선언 필요**  
- 배열이 const여도 포인터는 var로 선언 가능  
  
#### 포인터 역참조  
  
- 개별 배열 위치의 주소가 할당된 포인터는 포인터 산술로 업데이트 불가  
- **포인터 역참조는 `ptr.*` 사용**  
  
#### 레이블 브레이크  
  
- **컴파일 타임에 배열 초기화 등 다양한 작업 수행 가능**  
- **레이블 브레이크는 블록 이름 뒤에 `:`를 붙이고, `break`로 블록에서 값 반환**  
  - 예: `break :init m;`  
- `0..`는 0부터 시작하는 무한 범위  
- for 루프에서 변수들은 자동 초기화 및 증가되며, 배열 마지막 위치 처리 후 루프 종료  
- 배열은 `undefined`로 명시적으로 초기화하지 않을 수 있음  
  
#### Zig의 함수  
  
- **함수는 `fn`으로 선언하며 기본적으로 static (파일 내부에서만 사용)**  
  - `pub fn`으로 선언 시 다른 파일에서 import 가능  
- 함수는 "inlined" 가능  
- 함수 포인터는 `const`가 앞에 오고 함수 프로토타입이 뒤따름  
  
#### Zig의 객체지향 프로그래밍  
  
- **구조체는 함수를 가질 수 있음**  
- 스택 예제에서 최대 81개 요소(StkNode 타입) 저장 가능  
- **++ 및 -- 연산자는 Zig에 존재하지 않으며, += 및 -= 사용**  
- 스택 포인터는 `stk` 배열의 인덱스로 사용되는 정수  
- **포인터 `self`는 매개변수로 명시적으로 전달되지 않으며, 함수가 호출되는 스택 인스턴스의 포인터로 간접 가정**  
  - `stack.pop()`처럼 호출 시 `self`는 `stack`에 대한 포인터 (Java/C++의 `this`와 유사)  
- `init()` 함수는 스택 생성자  
- `pop`과 `push` 함수는 "inlined"  
  
### Zig 프로그램 빌드 및 실행  
  
#### 실행 파일 빌드  
  
- **실행 파일 생성을 위해 프로그램 진입점을 나타내는 `main` 함수 필요**  
- 간단한 프로그램은 main 함수를 같은 파일에 포함 가능  
- 모듈 독립 디버깅을 위해 파일 끝에 main 함수를 삽입한 후, 디버깅 완료 후 주석 처리 가능  
- 컴파일 명령: `zig build-exe -O ReleaseFast program.zig`  
  
#### 모듈의 테스트 블록 실행  
  
- **Zig의 가장 우수한 기능으로, 테스트와 프로토타이핑에 사용**  
- **테스트 블록은 `test "message" {`로 시작하여 `}`로 끝남**  
  - "message"는 테스트 실행 시 표시될 문자열  
- **테스트 블록은 실행 파일과 독립적으로 실행되며, 최종 실행 파일은 테스트를 실행하지 않음**  
- 테스트 명령: `zig test module.zig`  
- example.zig의 테스트 블록은 `set`과 `print` 함수를 테스트하며, set은 십진수 문자열을 매개변수로 받고, print는 "Input Grid" 헤더를 출력한 후 grid를 출력  
  
##### Zig의 출력  
  
- **`std.debug.print` 문은 표준 Zig 라이브러리 `std`의 `debug.zig`에 있는 `print` 함수 호출**  
- 첫 번째 매개변수는 형식 문자열, 두 번째는 표시할 변수 리스트를 포함하는 익명 구조체  
- 형식이 없는 경우 구조체는 비어 있음  
- 기본적으로 stderr에 표시  
- **C의 printf와 달리 Zig은 리터럴 문자열과 변수 리스트를 컴파일 타임에 처리 가능**  
  
#### 실행 파일 디버깅  
  
- 디버거 사용은 통합 디버거가 있는 IDE(Eclipse, IntelliJ IDEA) 또는 통합 개발 킷(w64devkit) 외에는 간단하지 않음  
- 심볼 통합은 코드를 비대화하고 Debug 모드 컴파일을 요구하여 효율성이 현저히 낮은 실행 코드 생성  
- **Zig은 이러한 문제를 피하기 위한 편리한 해결책 제공**  
  
##### @breakpoint 내장 함수  
  
- **소스 코드에 `@breakpoint();`를 삽입하여 디버거에서 실행 시 해당 지점에서 프로그램 중지**  
- **심볼 없이 최적화된 Zig 코드를 디버깅할 수 있는 유용한 기능**  
- `@breakpoint();` 직전에 `std.debug.print`를 사용하여 추적할 변수를 출력하면 해당 순간의 변수 값 확인 가능  
- debug_example.zig 예제에서 `set` 함수 내부에 grid와 변수들을 출력하는 코드와 `@breakpoint();` 삽입  
- 빌드 명령: `zig build-exe debug_example.zig`  
- gdb 같은 디버거로 debug_example.exe 호출 후 `r` 명령으로 프로그램 실행  
- `c` 명령으로 계속 진행하며 grid 내용과 변수 추적  
- Enter 반복 입력으로 계속 진행하면, grid의 값들이 example.zig의 테스트 블록과 일치함을 확인 가능  
  
### Zig의 저수준 프로그래밍  
  
#### 행렬 표현  
  
- **십진수 숫자는 표준 `u8` 정수로 행렬에 저장**  
- 입력 grid는 문자열 형식이지만 ASCII 문자는 내부적으로 u8 정수로 변환  
- **숫자 저장은 81개 위치의 배열 `grid`에 선형으로 한 줄씩 구성**: `var grid = [_]u8{0} ** 81;`  
- grid 정확성 검증을 위해 각 줄과 열로 요소 접근 필요  
- **9개 위치의 포인터 배열 생성, 각 포인터는 각 줄의 시작을 가리킴**  
- **레이블 브레이크를 사용하여 코드 블록에서 값 반환**: `break :fill9x9 m;`로 matrix를 m으로 초기화  
- 요소 접근 표기: `element = matrix[i][j]`  
  
#### 십진수 숫자를 비트로 표현  
  
- **정수 십진수 숫자 `i`를 정수 `code`로 대체하는 핵심 개념**  
  - `i ∈ [1,9] → code = 2ⁱ⁻¹`  
  - `i = 0 → code = 0`  
- **`code`의 유일한 비트가 `1`로 설정되는 위치는 `i-1` (i가 1~9 사이일 때), 그렇지 않으면 모든 비트가 0**  
- 각 숫자에 대한 code 값 표 제공 (1→1, 2→2, 3→4, ..., 9→256)  
  
##### Zig에서 code 계산  
  
- **`c`가 0이 아닐 때만 왼쪽 시프트 연산자로 `code` 값 계산**: `code = @as(u9,1) << (c-1);`  
- **Zig에서 상수는 연산이 컴파일되고 결과가 변수에 할당되려면 적절한 크기가 필요**  
- `code`는 u9 타입으로 선언 (최대값 256은 최소 9비트 필요)  
- **Zig은 임의 비트 크기 변수 보유 가능**  
- **내장 함수 `@as`로 `1` 상수를 u9 타입으로 캐스팅**  
  
#### 비트 필드를 사용한 grid 표현  
  
##### 줄별 비트 필드 grid  
  
- **배열 `lines`는 각 줄을 9비트 정수로 표현하여 전체 grid를 미러링**: `var lines = [_]u9{0} ** 9;`  
- **줄 `i`로 배열 접근 시, 특정 숫자가 해당 줄에 이미 있는지 비트 AND 연산(`&`)으로 확인**: `lines[i] & code`  
- 연산 결과가 0이면 숫자가 줄 i에 아직 없음, 그렇지 않으면 중복  
  
##### 열별 비트 필드 grid  
  
- **배열 `columns`는 각 열을 9비트 정수로 표현하여 전체 grid를 미러링**: `var columns = [_]u9{0} ** 9;`  
- **열 `j`로 배열 접근 시, 특정 숫자가 해당 열에 이미 있는지 비트 AND 연산으로 확인**: `columns[j] & code`  
- 연산 결과가 0이면 숫자가 열 j에 아직 없음, 그렇지 않으면 중복  
  
##### 스도쿠 규칙  
  
- 빈 스도쿠 grid에 새 숫자를 삽입할 때, **새 요소를 포함하는 전체 줄, 열, 셀에 이미 존재하지 않아야 함**  
- **셀은 굵은 선으로 구분된 9개의 3x3 grid 각각**  
- 9x9 grid의 각 특정 요소는 해당 요소를 포함하는 고유한 줄, 열, 셀을 가짐  
- 예제 grid에서 첫 번째 셀은 3, 5, 6, 8, 9를 포함하며, 1, 2, 4, 7이 누락  
- 배열 `lines`와 `columns`는 줄과 열의 중복 검사를 처리  
- **셀의 중복 검사를 위해 새 배열 필요**  
  
##### 셀별 비트 필드 grid  
  
- **배열 `cells`는 각 셀을 9비트 정수로 표현하여 전체 grid를 미러링**: `var cells = [_]u9{0} ** 9;`  
- **`cells`를 3x3 행렬로 접근하면 더 쉬움**  
- 9x9 행렬에서 수행한 것과 유사하게 배열 `cell` 채우기  
- 원래 9x9 grid의 요소 줄과 열에서 `cell` 행렬의 줄과 열 결정 필요  
- 정수 나눗셈은 매우 느리므로, **배열 `cindx = [_]usize{ 0,0,0, 1,1,1, 2,2,2 };`를 사용하여 나눗셈 결과 제공**  
- **9x9 grid의 요소 줄 `i`와 열 `j`로 행렬 접근 시, 특정 숫자가 요소의 셀에 이미 있는지 비트 AND 연산으로 확인**: `cell[cindx[i]][cindx[j]] & code`  
- 연산 결과가 0이면 숫자가 셀에 아직 없음, 그렇지 않으면 중복  
  
#### 요소 중복 테스트  
  
- **동일한 줄, 열, 셀의 모든 이전 요소를 비트 OR(`|`)로 결합한 후, 요소의 `code`와 비트 AND 수행하여 요소 중복 검증 완료**  
```  
if (((lines[i]|columns[j]|cell[cindx[i]][cindx[j]])&code) != 0) {  
    unreachable;  
}  
```  
- 결과가 0이면 요소가 아직 줄, 열, 셀에 존재하지 않음  
- 결과가 0이 아니면 프로그램은 `unreachable` 명령 실행으로 중지  
- **Zig에서 실행 오류를 명시적으로 나타내는 가장 간단한 방법**  
- 실제 코드는 오류 발생 위치의 세부 정보도 출력  
- 예: 입력 문자열의 첫 '8' 바로 다음 '0'을 '5'로 교체하면, 열 1의 줄 3에 이미 5가 있어 오류 발생  
  
#### 데이터 구조 업데이트  
  
- **`set` 함수에서 이중 for 루프가 줄별로 상호 작용하여 입력 문자열 `s`의 각 새 요소를 grid에 복사**  
  - 변수 `k`는 문자열 `s`의 새 입력 문자 인덱스 유지  
- **문자는 `'0'`을 빼서 `u4`(변수 `c`)로 변환**  
- grid에 삽입할 새 요소가 0이 아니면(`c != 0`), **왼쪽 시프트 명령으로 계산된 `code`를 각 미러 grid에 복사**  
  - 해당 미러 grid와 비트 OR(`|=`) 수행:  
```  
lines[i] |= code;  
columns[j] |= code;  
cell[cindx[i]][cindx[j]] |= code;  
```  
- **`c` 값이 1~9 사이인지 명시적으로 테스트할 필요 없음 - 시프트 연산 실행 시 오버플로가 발생하기 때문**  
- 예: 입력 문자열의 첫 '8' 바로 다음 '0'을 ':'로 교체하면 실행 오류 발생  
- 같은 '0'을 '/'로 교체해도 유사한 실행 오류 발생  
- 프로그램은 값이 1~9 사이, 즉 입력 grid가 십진수만 포함할 때만 작동  
- 웹의 많은 스도쿠 grid는 '0'을 '.'로 표현하므로, `set` 함수에 `if (s[k] == '.') c = 0;` 라인 존재  
- **이는 `c` 값이 0이므로 시프트 연산을 편리하게 우회**  
  
#### 프로토타이핑과 견고성  
  
- 위 두 섹션의 강제 오류는 Zig의 중요한 기능 시연  
- 하나는 **Zig의 견고성** - 시프트 연산의 경우 잘못된 동작이 허용되지 않으며 실행 시간에 포착됨  
- 모든 노력이 효율성을 향한 것처럼 보이지만, **성능이 견고성과 교환된 전형적인 사례**  
- C에서는 시프트 연산이 비트를 잃어도 프로그래머의 문제이며, 이는 특정 어셈블러 명령의 더 나은 성능으로 변환됨  
- 또 다른 기능은 **테스트 블록을 프로토타이핑에 사용할 가능성**  
- 응용 가능성은 무수히 많으며, 보여진 응용은 오류 발생 시 특정 상황을 디버깅하는 것뿐  
- **이러한 기능만으로도 프로그래밍 언어에서 매우 드문 놀라운 능력 제공**, 특히 컴파일된 프로그래밍 언어에서  
  
### 결론  
- Zig는 **C 호환성**, **크로스 컴파일**, **간단한 설치**라는 세 가지 핵심 요소로 구성  
- 이러한 특성은 **시스템 프로그래밍 언어의 새로운 표준**으로 자리 잡을 가능성을 보여줌  
- **인터프리터 언어에서만 발견되던 많은 장점이 더 나은 성능을 제공하기 위해 점차 컴파일 언어로 이동**  
- **Zig은 컴파일 타임 실행 개념으로 인터프리터 언어와의 유사성이 매우 두드러짐**  
- 이는 Zig을 특별히 다르고 강력하게 만드는 동시에 이해하기 어렵게 만들기도 함

## Comments



### Comment 46076

- Author: neo
- Created: 2025-11-08T18:33:16+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45852328) 
- 이 글은 처음엔 “Zig은 단순한 언어가 아니라 **완전히 새로운 프로그래밍 방식**”이라고 주장하지만, 실제로는 Zig만의 고유한 기능을 거의 다루지 않음  
  타입 추론, 익명 구조체, labeled break 등은 이미 오래전부터 다른 언어들에 존재했음  
  진짜 독특한 건 **comptime**인데, 이 부분은 전혀 언급되지 않음  
  Lisp 매크로처럼 완전히 새로운 개념은 아니지만, Zig이 이를 **제네릭 대신 사용하는 방식**은 흥미로움  
  하지만 글의 주장은 과장된 느낌이 강함
  - Rust도 마찬가지로 “완전히 새로운 방식”이라 할 수 있음  
    Rust는 코드 실행 시점을 명확히 표현할 수 있고, 전체 코드 공간을 탐색하는 **쿼리 엔진 같은 설계**가 인상적임
  - D 언어는 이미 2007년부터 **컴파일 타임 함수 실행**을 지원했음  
    [D 문서 링크](https://dlang.org/spec/function.html#interpretation) 참고  
    const-expression이면 자동으로 실행됨
  - C/C++을 하나로 묶는 건 이제 의미가 없음  
    Java/Scala처럼 완전히 다른 언어이기 때문임
  - comptime은 마법적인 발명이라기보다 **메타프로그래밍의 현대적 버전**임  
    Zig은 C++ 템플릿보다 깔끔하지만, 혁명적이라기보단 실용적인 대안 정도로 느껴짐  
    개인적으로는 Rust 때처럼 과도한 열광이 이해되지 않음
  - “완전히 새로운 방식”이라는 문구를 보고 LISP이나 Prolog 같은 **새로운 패러다임**을 기대했는데, 실제로는 그런 게 없었음  
    Zig 문서를 다 읽었는데도 놀랄만한 게 없어서 당황했음  

- Zig의 가장 큰 문제는 **에러에 데이터를 붙일 수 없다는 점**임  
  에러는 부가 채널로만 전달돼서 디버깅이 어렵고, 결국 개발자들이 에러 데이터를 생략하게 됨  
  [관련 이슈](https://github.com/ziglang/zig/issues/2647#issuecomment-1444790576) 참고  
  AccessDenied 같은 단순 코드만으로는 원인을 알기 힘듦
  - matklad의 [글](https://matklad.github.io/2025/11/06/error-codes-for-control-flow.html)을 읽었는데, 에러 코드와 진단 정보를 분리하는 접근이 설득력 있었음  
    실제로 복잡한 `Error` 객체를 써도 별도의 **진단 채널**이 필요할 때가 많음
  - 시스템 언어에서는 에러에 데이터를 붙이는 게 항상 좋은 건 아님  
    **성능 오버헤드**나 시스템 상태 문제 때문에, 상황에 따라 지연 바인딩으로 처리하는 게 더 안전함  
    Zig은 이런 **정밀성과 결정성**을 우선시하는 철학을 가짐
  - Zig에서도 에러 스택 트레이스에 **사용자 정의 정보**를 넣는 기능이 논의 중임  
    [관련 이슈](https://github.com/ziglang/zig/issues/14446) 참고  
    하지만 진짜 필요한 건 **구조적 로깅**과 호출 스택 기반의 문맥 추적 기능임
  - std.zon이 좋은 예시로 꼽히며, 커뮤니티에서 다양한 **에러 처리 패턴**을 모아 표준에 반영하려는 움직임이 있음
  - 에러에 데이터를 못 붙이게 하는 건 오히려 **명확한 에러 설계**를 유도함  
    게으른 개발자가 무조건 데이터를 덕지덕지 붙이는 걸 막을 수 있음  

- “Zig 개발 방식 자체가 새로운 언어 개발 방식”이라는 주장에 공감함  
  기능을 신중히 검토하고 불필요한 걸 제거하는 **느린 진화 과정**이 인상적임  
  - 하지만 이런 접근은 Java나 Rust 등에서도 흔함  
    Zig만의 독특한 점이 무엇인지 더 구체적으로 듣고 싶음  

- Zig을 **PyPI로 설치**할 수 있는 게 마음에 듦  
  [ziglang 패키지](https://pypi.org/project/ziglang/)를 `pip install ziglang`으로 설치하면 바로 사용 가능함  
  `uvx`를 이용해 C 코드를 빌드할 수도 있음  
  - Python wheel로 **임의의 소프트웨어를 번들링**할 수 있어서 이런 설치 방식이 가능함  
  - 하지만 이런 접근은 **nix보다 불편한 재발명**처럼 느껴짐  
  - Nim에도 이런 설치 옵션이 있었으면 좋겠음  
  - 개인적으로는 pip/uv보다 **micromamba나 pixi**가 더 나은 패키지 관리 방식이라 생각함  
  - AI 도구 덕분에 이제는 어떤 언어든 배우기가 훨씬 쉬워졌음  

- Ada, Object Pascal, Modula-2 같은 언어에서도 이미 존재하던 기능들을 Zig의 “혁신”으로 포장한 점이 아쉬움  
  **C 스타일 문법**으로 다시 포장되니 40년 전 아이디어가 새로워 보이는 현상이 흥미로움  

- 글의 도입부는 좋았지만, 이후엔 단순히 Zig 기능 나열로 끝남  
  Zig의 **직관적 문법**과 **명시적 제어 흐름**(defer 등)은 매력적임  
  comptime 덕분에 별도의 매크로 문법을 배울 필요도 없음  
  - Zig의 진짜 매력은 **불필요한 중복이 없는 설계**임  
    모든 구성요소가 자연스럽게 맞물려서, 처음 써도 오래 써온 도구처럼 느껴짐  
  - matklad의 [Zig 문법 분석 글](https://matklad.github.io/2025/08/09/zigs-lovely-syntax.html)도 참고할 만함  

- Zig의 `for (0..9)` 구문은 직관적이지만, **열린 구간**이라 종종 헷갈림  
  Python의 range(0, 9)처럼 마지막 값 포함 여부를 잊기 쉬움  
  - Rust는 `0..9`와 `0..=9`로 구분해서 명확함  
  - Zig처럼 **반열린 구간만 사용하는 일관성**이 오히려 오류를 줄임  
    구간 크기가 단순히 차이로 계산되고, 역방향 순회도 간단해짐  
  - Odin은 `0..<5`(열린)과 `0...5`(닫힌)으로 더 명시적으로 구분함  

- Zig의 **식별자 규칙**이 마음에 들지 않음  
  snake_case와 camelCase가 섞여 있어서 어색함  
  그래도 빌드 시스템, 메모리 할당자, 컴파일 경험 등은 훌륭함  
  Rust를 주로 쓰지만 Zig에 대한 **호기심**은 계속 있음  
  - 나도 비슷함. 개인적으로는 private 함수 네이밍 규칙을 따르지 않음  
    C 라이브러리의 접두사 규칙도 마찬가지로 귀찮음  

- Zig의 매력은 어떤 한 기능이 아니라, **실용적인 결정들의 누적**임  
  처음엔 급진적으로 보이던 선택들도, 이해가 깊어질수록 납득하게 됨  
  Zig은 **호기심 많은 개발자에게 보상해주는 언어**임  
  - Odin으로 작은 게임을 만들어봤는데, 정말 즐거운 경험이었음  

- Zig이 좋은 이유 중 하나는 **저수준 시스템 코드의 현실을 인정**한다는 점임  
  많은 언어들이 미학적 이유로 이런 부분을 외면하지만, Zig은 그렇지 않음  
  - 표준 라이브러리 정의로 이동해보면 Plan9 OS 같은 **특수 케이스 처리**도 직접 볼 수 있음  
    [page_allocator 문서](https://ziglang.org/documentation/master/std/#std.heap.page_allocator) 참고  
  - 다만 이런 주장을 뒷받침할 **구체적 예시**가 더 필요함
