원문 캡처 · ziglang.org
원문 캡처 · ziglang.org

Zig 개발 브랜치에 연산자 조합의 우선순위가 모호할 때 컴파일러가 괄호를 요구하는 변경이 적용됐다. 기존 코드는 컴파일러 오류를 따라 직접 수정하거나 zig fmt --upgrade로 괄호를 자동 추가해 업그레이드할 수 있다.

산술 연산자와 비교 연산자처럼 우선순위가 명확한 흔한 조합은 괄호 없이 쓸 수 있다. 반면 우선순위가 정의되지 않은 조합은 괄호를 써야 한다. Zig 개발팀은 이 변경으로 프로그래머가 기억해야 할 규칙을 줄이고, 우선순위를 잘못 기억해 생기는 버그를 줄이려 한다. 개발팀이 제시한 규모를 보면 Zig 코드베이스의 100만 줄 이상 가운데 수정이 필요했던 부분은 353줄이었다.

기존 코드를 옮기는 방법은 두 가지다. 컴파일러가 표시하는 ‘모호한 연산자 우선순위’ 오류를 하나씩 고치거나, zig fmt --upgrade를 실행할 수 있다. 이 옵션은 이전 우선순위 규칙에 따른 평가 순서를 유지하면서 괄호를 자동으로 추가하며, 한 번의 릴리스 주기가 지나면 제거될 예정이다.

Zig 개발팀은 오류를 하나씩 고치는 방법을 권장한다. 드문 연산자 조합의 의도된 평가 순서를 다시 확인하는 과정에서 버그를 발견할 수 있기 때문이다. 자동 수정 방식을 택하더라도 변경 내용을 검토하라고 권한다. zig fmt --upgrade는 불필요한 괄호를 넣을 수 있고, 자동 수정 결과가 코드 작성자의 의도와 다르게 보일 수도 있다.

자세한 우선순위 규칙은 Zig 언어 레퍼런스의 우선순위 항목에서 확인할 수 있다. 이 변경은 기여자 CMDRZero가 구현했으며, Isaac Freund가 문법 변경을 도왔다.

부록: 원문 예시

text
$ strace ./hello_threaded execve("./hello_threaded", ["./hello_threaded"], 0x7ffc1da88b20 /* 98 vars */) = 0 mmap(NULL, 262207, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f583f338000 arch_prctl(ARCH_SET_FS, 0x7f583f378018) = 0 prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 prlimit64(0, RLIMIT_STACK, {rlim_cur=16384*1024, rlim_max=RLIM64_INFINITY}, NULL) = 0 sigaltstack({ss_sp=0x7f583f338000, ss_flags=0, ss_size=262144}, NULL) = 0 sched_getaffinity(0, 128, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31]) = 8 rt_sigaction(SIGIO, {sa_handler=0x1019d90, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x10328c0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGPIPE, {sa_handler=0x1019d90, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x10328c0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 writev(1, [{iov_base="Hello, World!\n", iov_len=14}], 1Hello, World! ) = 14 rt_sigaction(SIGIO, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x10328c0}, NULL, 8) = 0 rt_sigaction(SIGPIPE, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x10328c0}, NULL, 8) = 0 exit_group(0)                           = ? +++ exited with 0 +++ 
text
execve("./hello_evented", ["./hello_evented"], 0x7fff368894f0 /* 98 vars */) = 0 mmap(NULL, 262215, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70a4c28000 arch_prctl(ARCH_SET_FS, 0x7f70a4c68020) = 0 prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 prlimit64(0, RLIMIT_STACK, {rlim_cur=16384*1024, rlim_max=RLIM64_INFINITY}, NULL) = 0 sigaltstack({ss_sp=0x7f70a4c28008, ss_flags=0, ss_size=262144}, NULL) = 0 sched_getaffinity(0, 128, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31]) = 8 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70a4c27000 mmap(0x7f70a4c28000, 548864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70a4ba1000 io_uring_setup(64, {flags=IORING_SETUP_COOP_TASKRUN|IORING_SETUP_SINGLE_ISSUER, sq_thread_cpu=0, sq_thread_idle=1000, sq_entries=64, cq_entries=128, features=IORING_FEAT_SINGLE_MMAP|IORING_FEAT_NODROP|IORING_FEAT_SUBMIT_STABLE|IORING_FEAT_RW_CUR_POS|IORING_FEAT_CUR_PERSONALITY|IORING_FEAT_FAST_POLL|IORING_FEAT_POLL_32BITS|IORING_FEAT_SQPOLL_NONFIXED|IORING_FEAT_EXT_ARG|IORING_FEAT_NATIVE_WORKERS|IORING_FEAT_RSRC_TAGS|IORING_FEAT_CQE_SKIP|IORING_FEAT_LINKED_FILE|IORING_FEAT_REG_REG_RING|IORING_FEAT_RECVSEND_BUNDLE|IORING_FEAT_MIN_TIMEOUT|IORING_FEAT_RW_ATTR|IORING_FEAT_NO_IOWAIT, sq_off={head=0, tail=4, ring_mask=16, ring_entries=24, flags=36, dropped=32, array=2112, user_addr=0}, cq_off={head=8, tail=12, ring_mask=20, ring_entries=28, overflow=44, cqes=64, flags=40, user_addr=0}}) = 3 mmap(NULL, 2368, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, 3, 0) = 0x7f70a4ba0000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, 3, 0x10000000) = 0x7f70a4b9f000 io_uring_enter(3, 1, 1, IORING_ENTER_GETEVENTS, NULL, 8Hello, World! ) = 1 io_uring_enter(3, 1, 1, IORING_ENTER_GETEVENTS, NULL, 8) = 1 munmap(0x7f70a4b9f000, 4096)            = 0 munmap(0x7f70a4ba0000, 2368)            = 0 close(3)                                = 0 munmap(0x7f70a4ba1000, 548864)          = 0 exit_group(0)                           = ? +++ exited with 0 +++