Tập 85: Module visibility — Xây dựng biên giới cho dự án

Khi dự án DUY vượt qua mốc 10.000 dòng code, chúng tôi nhận ra cấu trúc module phẳng của thuở ban đầu đã bộc lộ giới hạn. Nếu mọi struct và hàm đều công khai (public) mặc định, việc duy trì tính toàn vẹn của thư viện là bất khả thi. Lập trình viên có thể vô tình gọi các hàm internal của thư viện, tạo ra các mối liên kết chặt chẽ và phá vỡ cấu trúc đóng gói.

Sprint 141 và 146 giải quyết bài toán này bằng cách đưa vào từ khóa pub và quy tắc đóng gói nghiêm ngặt. Mọi định nghĩa trong DUY mặc định là private đối với module chứa nó. Chỉ khi có từ khóa pub, biên giới mới được mở ra.

// file: math.duy
pub struct Point {
  pub x: i32,
  pub y: i32
}

fn internal_helper() { ... } // private

Nhưng vấn đề phức tạp hơn nằm ở re-export (pub import) và bài toán dependencies vòng tròn (circular imports). Để Type Checker có thể thực thi luật kiểm tra tầm vực trên toàn bộ đồ thị module, chúng tôi phải triển khai thuật toán tính toán transitive closure để xây dựng một bản đồ visibleModulesMap cho mỗi tệp tin.

Nếu Module A import Module B, và Module B import Module C dưới dạng pub import, thì Module A có quyền nhìn thấy các ký hiệu của Module C. Nhưng nếu xuất hiện vòng lặp A -> B -> A, trình phân giải đồ thị (resolver) phải phát hiện và ném ra lỗi Circular import ngay lập tức để tránh làm cạn kiệt bộ nhớ của compiler trong quá trình duyệt đệ quy vô hạn.

Tôi đã mất cả buổi chiều để sửa một bug trong đó resolver của native compiler bị lặp vô tận khi gặp hai module import chéo nhau. Sau khi thêm cơ chế đánh dấu vết duyệt (visited set) vào thuật toán phân giải import, compiler đã phát hiện vòng lặp chính xác và báo lỗi rõ ràng. Biên giới của dự án đã có những chốt canh gác nghiêm ngặt.


Bình luận (0)

Đang tải bình luận...