- Logic phân giải kiểu (type resolution) của trình biên dịch Zig đã được thiết kế lại toàn diện, giúp đơn giản hóa cấu trúc nội bộ và mang lại những cải thiện rõ rệt cho người dùng
- Thiết kế mới trì hoãn (lazy) việc phân tích các trường của kiểu, nên không kiểm tra không cần thiết cấu trúc chi tiết của các kiểu chưa được khởi tạo
- Thông báo lỗi vòng lặp phụ thuộc (dependency loop) đã được cải thiện cụ thể hơn, giúp xác định rõ nguyên nhân của vòng lặp
- Vấn đề phân tích quá mức và nhiều lỗi trong tính năng biên dịch tăng dần (incremental compilation) đã được khắc phục, giúp tốc độ build cải thiện đáng kể
- Thay đổi lần này bao gồm hàng chục bản sửa lỗi và các cải tiến ngôn ngữ nhỏ, qua đó nâng cao toàn diện hiệu năng và trải nghiệm phát triển của trình biên dịch Zig
Thiết kế lại logic phân giải kiểu
- Một PR quy mô khoảng 30.000 dòng đã được hợp nhất, viết lại logic phân giải kiểu của trình biên dịch Zig theo cấu trúc logic và trực quan hơn
- Trong quá trình này, cấu trúc nội bộ của trình biên dịch đã được sắp xếp lại, đồng thời người dùng cũng nhận được lợi ích cải thiện trực tiếp
- Trình biên dịch được thay đổi để đánh giá lười việc phân tích trường của kiểu, nên không còn duyệt không cần thiết vào cấu trúc chi tiết của các kiểu chưa được khởi tạo
- Trong mã ví dụ, khi một struct chứa trường
@compileError chỉ được dùng như namespace, trước đây sẽ phát sinh lỗi biên dịch nhưng giờ đây có thể biên dịch bình thường
- Điều này giúp tránh phụ thuộc mã không cần thiết khi sử dụng các kiểu dạng namespace như
std.Io.Writer
Cải thiện thông báo lỗi vòng lặp phụ thuộc
- Trước đây, thông báo lỗi vòng lặp phụ thuộc khá mơ hồ, nhưng nay đã hiển thị rõ nguyên nhân và vị trí của vòng lặp
- Trong mã ví dụ, khi hai struct
Foo và Bar tham chiếu lẫn nhau, thông báo lỗi sẽ chỉ ra cụ thể vị trí phụ thuộc của từng kiểu
- Thông báo bao gồm độ dài vòng lặp, vị trí khai báo từng trường, và vị trí truy vấn căn chỉnh
- Ngay cả với các vòng lặp phức tạp, thông báo vẫn cung cấp đủ thông tin để dễ dàng xác định nguyên nhân vấn đề
Cải thiện hiệu năng biên dịch tăng dần
- Thay đổi lần này đã sửa nhiều lỗi trong tính năng biên dịch tăng dần
- Đặc biệt, vấn đề “phân tích quá mức (over-analysis)” đã được giải quyết, tối ưu để chỉ biên dịch lại những phần đã thay đổi
- Kết quả là trong nhiều trường hợp, tốc độ biên dịch được cải thiện đáng kể
- Nhà phát triển có thể bật biên dịch tăng dần trên Zig 0.15.1 trở lên để trải nghiệm quy trình phát triển được cải thiện
Các cải tiến khác
- PR lần này bao gồm hàng chục bản sửa lỗi, thay đổi ngôn ngữ nhỏ, và cải thiện hiệu năng trình biên dịch
- Phần lớn là các trường hợp chi tiết hoặc đặc thù
- Có thể xem toàn bộ thay đổi trên Codeberg tại PR #31403
- Khuyến khích báo cáo issue nếu phát hiện lỗi mới
Ý nghĩa của thay đổi
- Việc đơn giản hóa logic phân giải kiểu và tối ưu biên dịch tăng dần đã tăng cường độ ổn định và hiệu quả của trình biên dịch Zig
- Nhà phát triển sẽ nhận được phản hồi nhanh hơn và rõ ràng hơn, đồng thời có thể kỳ vọng nâng cao năng suất ngay cả với codebase quy mô lớn
1 bình luận
Ý kiến trên Hacker News
Tôi là tác giả của devlog này
Tôi hiểu những lo ngại về việc phá vỡ khả năng tương thích do thay đổi ngôn ngữ, nhưng muốn nói rõ rằng thay đổi lần này của trình biên dịch không ở mức gây ảnh hưởng lớn
Ví dụ, khi build ZLS bằng nhánh mới, tôi chỉ cần sửa kiểu thay
.{}thành.empty. Đây là do việc loại bỏ giá trị mặc định củastd.ArrayList, và nó đã ở trạng thái deprecated từ 1 năm trướcVới dự án Awebo cũng vậy, trong toàn bộ cây phụ thuộc chỉ có ba chỗ cần sửa — đổi sang
.empty, thêmcomptime, và thêmorelse @alignOf(T)Phần lớn những chỉnh sửa này đều là thay đổi đơn giản ở mức mà hầu hết lập trình viên Zig sẽ xử lý gần như theo phản xạ
Trọng tâm của PR lần này không phải là gây vỡ, mà là sửa lỗi và cải thiện biên dịch gia tăng
Tôi nghĩ chất lượng và mức độ chuẩn bị của PR là rất cao, hoàn toàn không có ý hạ thấp công sức của tác giả
Chỉ là tôi rút ra bài học rằng sau này nên thêm nhiều chú thích hơn và để lại ý kiến cẩn trọng hơn
lib/std/multi_array_list.zigthì có một điều khiến tôi thắc mắcTôi không hiểu vì sao việc dùng
@alignOf(T)trong định nghĩaMultiArrayList(T)lại tạo ra phụ thuộc vòngDù
Tcó là chínhMultiArrayListthì đó chẳng phải vẫn là một kiểu monomorphic hoàn toàn tách biệt sao? Có lẽ tôi đang bỏ sót điều gì đóMã liên quan: liên kết
Tôi tò mò về trải nghiệm của những người dùng Zig trong môi trường production
Ngôn ngữ thay đổi thường xuyên, nên tôi muốn biết chu kỳ cập nhật hay rewrite thường ra sao, và liệu có trường hợp các gói phụ thuộc bị chậm hơn so với phiên bản ngôn ngữ hay không
Tôi biết Bun đang tận dụng Zig rất tốt, nhưng cũng muốn nghe thêm các trường hợp khác
Trong 1~2 năm qua, các thay đổi của ngôn ngữ và thư viện chuẩn diễn ra không có vấn đề lớn
Trước đây việc nâng cấp khá phiền, nhưng giờ chỉ còn cảm giác như “hơi bất tiện một chút”
Nếu ai hỏi về trải nghiệm dùng Zig, thì phần này ổn định đến mức tôi gần như còn không nhắc tới
Những dự án lớn như vậy nâng cấp dựa trên các bản phát hành đã gắn thẻ, và thường hoàn tất migration trong vài ngày đến vài tuần
Chúng cũng gần như không có phụ thuộc, nên gánh nặng nâng cấp không lớn
Tuy vậy, đôi khi chỉ một lỗi gõ nhỏ cũng có thể gây crash trình biên dịch SIGBUS, khiến việc debug rất khó
.zig-cachetừng phình tới 173GB, gây vấn đề trên VPS ARMKhi nâng
lightpandatừ 0.14 lên 0.15 thì mọi thứ khá suôn sẻ. Có lẽ 0.16 cũng sẽ không có vấn đề lớnNhưng với tư cách là người phát triển thư viện, tôi thấy khó theo kịp tốc độ thay đổi nhanh của 0.16
Hiện tại tôi chỉ hỗ trợ thử nghiệm trên nhánh “dev”
Tôi đã rewrite một module Node.js/TypeScript sang Zig, và kết quả là nhanh gấp 2 lần, dùng ít hơn 70% bộ nhớ
Hỗ trợ
sqlite/serializeJSONcủa Zig rất mạnh, đó là một lợi thế lớnĐiểm trừ là thiếu cú pháp closure hoặc vtable, nên khó tách lớp mã nguồn
Tôi dùng
Arcsvà bộ cấp phát bumper để đảm bảo an toàn bộ nhớ, và dự định tiếp tục chạy ở DebugSafeChuyển sang ReleaseFast có giúp tăng thêm 25% hiệu năng, nhưng chưa đáng để đánh đổi sự an toàn
Dù phải sửa mã nguồn, về lâu dài đây vẫn là cách tiếp cận đúng đắn
Tôi rất ấn tượng với những gì đội ngũ Zig làm được
Tôi hay dùng terminal ghostty viết bằng Zig, và nó rất ổn định
Nhưng cá nhân tôi vẫn thích Rust hơn
Rust chọn mô hình “thế giới đóng”, còn Zig chọn “thế giới mở”
Rust yêu cầu implement trait một cách tường minh, trong khi Zig chỉ cần hình dạng (shape) của kiểu phù hợp là hoạt động
Nhờ vậy Zig có thể metaprogramming rất mạnh, nhưng nhược điểm là suy luận kiểu thiếu rõ ràng nên autocomplete, tài liệu hóa, hỗ trợ LSP trở nên khó hơn
Nghe mô tả thì khá giống interface của Go, nhưng tôi biết Zig dường như không có khái niệm tương ứng trực tiếp
Việc chuyển từ
kernel32sangNtdllkhá thú vịĐây là một ý tưởng cũng có thể áp dụng cho API user-space của Linux
Đặc biệt là cách xử lý lỗi ở ranh giới kernel-user có nét tương đồng
Tuy nhiên trên Linux thì libc và kernel gắn chặt với nhau nên việc dùng
errnolà bắt buộcTôi tò mò vì sao trên Windows cũng xuất hiện kiểu mẫu này
errnohayGetLastError()là di sản từ thời trước khi có threadNgày xưa lập lịch cộng tác khiến biến toàn cục vẫn an toàn, nhưng khi multicore và thread xuất hiện thì điều đó trở nên nguy hiểm
Vì thế thread local đã xuất hiện như một phương án thay thế
Thay vì dùng kiểu như namespace, tôi nghĩ có lẽ tốt hơn là thêm namespace tường minh vào ngôn ngữ
Nếu một tính năng tối ưu được ở nhiều nơi, thì đến lúc đó họ mới thêm vào theo cách tiếp cận này
Trong Zig,
@importbiến file thành một struct, còn namespace đơn giản được biểu diễn bằng struct lồng nhauNói cách khác, namespace cũng chỉ là một import khác mà thôi
(Tôi chưa tỉnh cà phê hẳn nên không dám đảm bảo chính xác tuyệt đối)
Có một điều thường bị bỏ qua trong các cuộc thảo luận về thay đổi ngôn ngữ — đó là tác động tới hệ sinh thái
Nếu ngôn ngữ thường xuyên bị phá vỡ, thì không chỉ ứng dụng mà cả thư viện, công cụ, tutorial cũng phải liên tục chạy theo
Kết quả là hệ sinh thái sẽ nghiêng về các dự án được bảo trì tích cực hơn là những thư viện “làm một lần rồi bỏ đó”
Đây là một trade-off hợp lý ở giai đoạn thiết kế ngôn ngữ ban đầu, nhưng về lâu dài nó sẽ ảnh hưởng đến tăng trưởng của hệ sinh thái
Nhiều ngôn ngữ mới khác đang đầu tư rất nhiều công sức để giảm thiểu sự mệt mỏi vì thay đổi này
Sẽ rất thú vị khi theo dõi xem cách tiếp cận của Zig sẽ dẫn đến kết quả gì
Blender thường xuyên phá vỡ API, nhưng phần lớn chỉnh sửa đều nhỏ
Tuy vậy vẫn phải có ai đó đi sửa, và nếu bảo trì bị ngưng thì người dùng sẽ phải tự vá lấy
Addon trả phí có khả năng được duy trì cao hơn, nhưng điều đó cũng không được đảm bảo
Thư viện không được bảo trì thì đằng nào cũng là mã tệ
Thay vì chỉ trích Zig, mong mọi người đừng tranh thủ quảng bá các ngôn ngữ khác (như C3)
Nội dung trong PR của Zig nói rằng “Chromium, boringssl, Firefox, Rust gọi
SystemFunction036của advapi32.dll” thực ra là không đúngHọ đã dùng ProcessPrng rồi, và từ Windows 10 trở đi nó không thất bại
Cơ sở liên quan nằm trong whitepaper của Microsoft
Cơ chế này được thiết kế để yêu cầu RNG tuyệt đối không thể thất bại, và nếu có lỗi thì chính tiến trình sẽ bị chấm dứt
Nói cách khác, để đảm bảo số ngẫu nhiên chất lượng cao, nó không trả về mã lỗi
Ngữ nghĩa ngôn ngữ của Zig nhìn bề ngoài thì đơn giản, nhưng tương tác giữa các phần lại khá tinh tế
Điều này khiến tôi nghĩ rằng theo thời gian nó có thể sinh ra những trường hợp góc cạnh phức tạp giống như các quy tắc template của C++
Một PR 30 nghìn dòng là thành tựu rất lớn
Nhưng việc thay đổi ngữ nghĩa ngôn ngữ là chuyện cực kỳ hệ trọng, nên tôi khá bất ngờ
Tôi hiểu Zig còn chưa tới 1.0 nên thay đổi nhanh, nhưng kiểu diễn đạt casual như “đã đổi ngữ nghĩa ở nhánh này” vẫn khiến tôi hơi sửng sốt
Tôi tò mò không biết đây có phải văn hóa đặc trưng của Zig hay chỉ là tôi đã lạc hậu rồi
Cụm “modern Zig” cũng khiến tôi bật cười vì tốc độ thay đổi quá nhanh của ngôn ngữ
Devlog không phải bài marketing mà gần với ghi chép nội bộ cho người trong cuộc, và Zig vẫn chưa phải 1.0
PR có đầy đủ bối cảnh và căn cứ
Khi đã chọn Zig thì coi như cũng chấp nhận một mức rủi ro thay đổi ngôn ngữ nhất định
Ngược lại, dọn dẹp cho gọn gàng ngay từ bây giờ về lâu dài lại có lợi hơn
(Cứ nghĩ đến những di sản không thể sửa được như thứ tự ưu tiên toán tử bit của C là hiểu)
mlugglà người đóng góp cốt lõi của Zig và cũng là thành viên Zig FoundationThay đổi lần này nhằm giải quyết phụ thuộc vòng và sắp xếp lại hệ thống kiểu
Các đề xuất liên quan đã được công khai ở #3257 và #15909
Nhờ thay đổi này, quá trình phân giải kiểu của Zig được tổ chức thành cấu trúc DAG (đồ thị có hướng không chu trình), giúp độ ổn định của trình biên dịch tăng lên đáng kể
Zig được vận hành theo mô hình BDFN (Benevolent Dictator For Now), với quyền quyết định cuối cùng thuộc về Andrew Kelley
Tuy vậy đội ngũ là một tổ chức phi lợi nhuận và luôn đặt niềm tin của người dùng và chất lượng ngôn ngữ lên hàng đầu
Cá nhân tôi thấy được làm việc cùng Matthew là một vinh dự lớn
Nó gợi nhớ đến C — một ngôn ngữ trên danh nghĩa thì chặt chẽ, nhưng thực tế lại là một mớ hỗn độn