- Ra đời giữa tình trạng hỗn loạn phần mềm của Bộ Quốc phòng Mỹ trong thập niên 1970, Ada là một ngôn ngữ lấy kiểu tĩnh mạnh và sự tách biệt giữa đặc tả với triển khai làm cốt lõi
- Thông qua cấu trúc package và ẩn biểu diễn, Ada hiện thực hóa đóng gói hoàn chỉnh, và sau đó ảnh hưởng đến hệ thống mô-đun của các ngôn ngữ hiện đại như Java, C# và Go
- Kiểu ràng buộc ngữ nghĩa, generic, đồng thời (task), thiết kế theo hợp đồng là những khái niệm Ada đã đưa ra trước hàng chục năm, rồi được Haskell, Rust, Swift và các ngôn ngữ khác kế thừa
- SPARK Ada loại bỏ cả tranh chấp dữ liệu lẫn lỗi logic thông qua kiểm chứng hình thức, và được dùng trong các lĩnh vực đòi hỏi độ tin cậy cao như hàng không, đường sắt và hệ thống quốc phòng
- Dù không phải ngôn ngữ phổ biến đại chúng, Ada vẫn là “ngôn ngữ âm thầm vận hành một cách đúng đắn”, nền tảng đã đặt ra các nguyên tắc cốt lõi cho thiết kế ngôn ngữ lập trình hiện đại
Bối cảnh ra đời và triết lý thiết kế của Ada
- Đầu thập niên 1970, Bộ Quốc phòng Mỹ (DoD) khảo sát tình trạng hơn 450 ngôn ngữ và phương ngữ cùng tồn tại trong các hệ thống vũ khí, hậu cần và truyền thông
- Mỗi hệ thống đều gặp các vấn đề như không thể tương tác, không thể bảo trì, hoặc tác giả ban đầu không còn nữa
- Điều này dẫn đến khủng hoảng mua sắm phần mềm
- Thay vì chọn một ngôn ngữ có sẵn như COBOL, Fortran hay PL/1, DoD đã trải qua quy trình xác định yêu cầu kéo dài 5 năm
- Tài liệu phát triển theo các giai đoạn Strawman → Woodenman → Tinman → Ironman → Steelman
- Steelman (1978) yêu cầu tách biệt giao diện một cách tường minh, kiểu tĩnh mạnh, đồng thời tích hợp sẵn, xử lý ngoại lệ nhất quán, độc lập máy, dễ đọc và có thể kiểm chứng
- Trong cuộc cạnh tranh giữa 4 nhóm vào năm 1979 (Green, Red, Blue, Yellow), nhóm Green do Jean Ichbiah dẫn dắt đã được chọn, và ngôn ngữ được đặt tên là Ada
- Cái tên này nhằm tôn vinh Ada Lovelace, đồng thời tượng trưng cho chủ đích của ngôn ngữ
Cấu trúc package và đóng gói
- Cấu trúc trung tâm của Ada là package, trong đó specification và body được tách biệt vật lý
- Specification là hợp đồng công khai ra bên ngoài, còn body là phần triển khai; trình biên dịch ép buộc mối quan hệ giữa hai phần này
- Mã client không thể truy cập vào các thành phần không có trong specification
- Cấu trúc này là nguyên mẫu của hệ thống mô-đun, và các ngôn ngữ về sau chỉ mô phỏng lại một phần
- Java, Python, JavaScript, C, Go, Rust đều chưa hiện thực được sự tách biệt cấu trúc hoàn chỉnh như Ada
- Kiểu
private chỉ lộ tên, còn biểu diễn bên trong thì hoàn toàn mờ đục
- Client không thể biết cấu trúc nội bộ của kiểu, và chỉ có thể dùng các phép toán được cho phép
- Đây là ẩn biểu diễn (representational invisibility) mạnh hơn cả kiểm soát truy cập
private của Java
- Java và C# đã phát triển dần trong nhiều thập niên để tiến tới mức đóng gói như Ada
Hệ thống kiểu và ràng buộc ngữ nghĩa
- Ada định nghĩa sự phân biệt giữa type và subtype theo nghĩa toán học
- Ví dụ:
type Age is range 0 .. 150 tạo ra một kiểu riêng với ràng buộc phạm vi
- Việc truyền sai giữa các kiểu sẽ bị phát hiện thành lỗi thời điểm biên dịch
- Ở thời điểm năm 1983, hệ thống kiểu của Ada biểu đạt mạnh hơn rất nhiều so với C, Fortran và Pascal
- Kiểu ràng buộc ngữ nghĩa giúp ngăn lỗi ở mức miền nghiệp vụ
- Bản ghi phân biệt (discriminated record) là cấu trúc có các trường khác nhau tùy theo giá trị
- Đây chính là sum type hay kiểu dữ liệu đại số (ADT) trong các ngôn ngữ hiện đại
- Haskell, Rust, Swift, Kotlin, TypeScript và nhiều ngôn ngữ khác đã đưa cùng khái niệm này vào sau đó hàng chục năm
Generic và đa hình
- Generic của Ada là đơn vị có thể nhận kiểu, giá trị, chương trình con và package làm tham số
- Nó hiện thực đa hình tĩnh (parametric polymorphism) với việc kiểm tra kiểu ngay khi biên dịch
- C++ (1990), Java (2004), C# (2005), Go (2022) và các ngôn ngữ khác đã mất hàng chục năm sau Ada mới đưa vào các tính năng tương tự
- Java dùng type erasure, làm mất thông tin kiểu lúc chạy
- Ada vẫn giữ được kiểu lúc chạy và còn hỗ trợ tham số hóa package
- Generic của Ada cung cấp mức độ biểu đạt tương đương higher-kinded polymorphism
- Tương tự với type class của Haskell, trait của Rust, hay concepts trong C++20
Mô hình đồng thời và độ an toàn
- Từ năm 1983, Ada đã tích hợp đồng thời ở cấp ngôn ngữ (task)
- Thông qua khai báo
task và mô hình giao tiếp rendezvous, nó hiện thực truyền thông điệp không cần chia sẻ trạng thái
- Channel của Go thuộc cùng họ khái niệm CSP (Communicating Sequential Processes)
- Ada 95 đưa vào protected object
- Nó bảo vệ truy cập dữ liệu và phân chia thành
procedure, function, entry
- Cung cấp điều kiện chặn tự động và đồng bộ hóa không khóa
- SPARK Ada dùng kiểm chứng hình thức để chứng minh bằng toán học rằng không có tranh chấp dữ liệu, ngoại lệ, lỗi phạm vi, hay vi phạm điều kiện trước/sau
- Trong khi borrow checker của Rust chỉ bảo đảm an toàn bộ nhớ, SPARK còn chứng minh được cả tính nhất quán logic
Thiết kế theo hợp đồng và an toàn null
- Ada 2012 tích hợp hợp đồng (contracts) vào trong ngôn ngữ
- Có thể khai báo precondition, postcondition, và invariant của kiểu
- Chuỗi công cụ SPARK tận dụng các yếu tố này cho việc chứng minh tĩnh
- Khái niệm Design by Contract của Eiffel (1986) được Ada chính thức hóa ở cấp ngôn ngữ
- C++, Java, Python, Rust và các ngôn ngữ khác vẫn chỉ dừng ở mức triển khai một phần hoặc ở cấp thư viện
- Ada 2005 đưa vào kiểu
not null để hỗ trợ loại trừ null ngay lúc biên dịch
- Mặc định, nó bảo đảm thất bại an toàn bằng ngoại lệ thời gian chạy (
Constraint_Error)
- Cách tiếp cận này tương tự nullable reference của C# 8.0
Cấu trúc xử lý ngoại lệ
- Ada 83 là ngôn ngữ đầu tiên đưa vào xử lý ngoại lệ có cấu trúc (structured exception handling)
- Ngoại lệ được khai báo rồi mới sử dụng, được xử lý theo phạm vi, và có quy tắc lan truyền rõ ràng
- Checked exception của Java là một dạng phát triển hơn so với Ada, trong đó bên gọi phải khai báo ngoại lệ
- Ada cho phép lan truyền ngoại lệ tự do hơn
- Rust loại bỏ ngoại lệ và chọn xử lý lỗi dựa trên kiểu
Result
- Đóng góp của Ada là làm cho việc lan truyền ngoại lệ trở nên có cấu trúc và có thể dự đoán được
Annex và cấu trúc tiêu chuẩn hóa
- Chuẩn Ada có cấu trúc mở rộng tùy chọn gọi là Annex
- Annex C~H định nghĩa các tính năng cho hệ thống, thời gian thực, phân tán, số học và các lĩnh vực độ tin cậy cao
- Trình biên dịch phải nhận chứng nhận độc lập cho từng Annex
- ACAA dùng bộ kiểm thử ACATS để xác minh mức độ tuân thủ chuẩn
- Cấu trúc chuẩn của Ada có thể được áp dụng trực tiếp vào chứng nhận phần mềm hàng không DO-178C
- C/C++ cũng có thể đạt chứng nhận tương tự, nhưng Ada phù hợp hơn về mặt cấu trúc
Ảnh hưởng của Ada và sự mất cân bằng trong nhận thức
- Ada là một ngôn ngữ do chính phủ dẫn dắt, nên không được chú ý nhiều trong văn hóa công nghệ kiểu Silicon Valley
- Điều này đối lập với xu hướng ưa chuộng cú pháp ngắn gọn dựa trên C
- Các trường hợp thành công của Ada (hàng không, đường sắt, hệ thống quốc phòng) ít hiện diện vì không có thất bại
- Những hệ thống có độ tin cậy cao không tạo ra tranh luận hay sự cố để thu hút chú ý
- Hướng phát triển của các ngôn ngữ hiện đại đang hội tụ về những nguyên tắc mà Ada đã nêu ra từ trước
- Như tách biệt đặc tả và triển khai, kiểm tra kiểu tĩnh, đồng thời ở cấp ngôn ngữ, an toàn dựa trên hợp đồng
- Ada hiện vẫn đang vận hành trong các hệ thống độ tin cậy cao như máy bay, đường sắt và tàu vũ trụ,
và vẫn là “ngôn ngữ âm thầm vận hành một cách đúng đắn”
1 bình luận
Ý kiến Hacker News
Tôi thích Ada. Nhưng khi bàn về xử lý kiểu mà lại hoàn toàn bỏ qua các ngôn ngữ họ ML (ML, SML, CML, Caml, OCaml, v.v.) thì thật đáng ngạc nhiên
Các ngôn ngữ này hỗ trợ kiểu cấu trúc ở cấp trình biên dịch. Vấn đề của Ada là bản thân ngôn ngữ quá lớn và cú pháp quá phức tạp, giống như PL/I, PHP, Perl. Bài viết xem đó là ưu điểm, nhưng cá nhân tôi cho rằng các phần mở rộng tiêu chuẩn được tách ra thành Annex còn hay hơn. Nếu ngôn ngữ lõi được giữ nhỏ gọn và đi theo hướng lấy Annex làm trung tâm, có lẽ nó đã được dùng rộng rãi hơn
Một trong những lý do Ada bị ghẻ lạnh là vì giá trình biên dịch lên tới hàng chục nghìn đô la. Thời chưa có trình biên dịch miễn phí hay mã nguồn mở, các ngôn ngữ khác có thể dùng miễn phí. Đó là yếu tố mang tính quyết định
Khi đọc bài, tôi thấy cả Ada lẫn chính bài viết đều thú vị, nhưng có vài lỗi thực tế khá dễ thấy. Ví dụ, bài nói chỉ Ada mới tách biệt hoàn toàn implementation và specification, nhưng JavaScript cũng có thể định nghĩa các phần tử private trong module ES6. Phần giải thích về mức truy cập
privatecủa Java cũng sai. Những lỗi kiểu này làm độ tin cậy của bài giảm điprivatethì bên ngoài không thể truy cập các trường nội bộ. Ngược lại, trong JavaScript, với bất kỳ object nào bạn cũng có thể tự do thêm hoặc xóa thuộc tính. Nói cách khác, mức bảo vệ lúc biên dịch của Ada không thể đem so với JSsetAccessible(true), thậm chí còn có thể sửa nội bộ của StringTổng thể bài viết khá hay, nhưng câu kiểu “ngôn ngữ X có tính năng này muộn hơn Ada” cứ lặp đi lặp lại nên khá chán. Nếu có ví dụ mã thì có lẽ sẽ thuyết phục hơn nhiều
Tài khoản Twitter này được tạo vào tháng 4 năm 2026 và không ghi rõ tác giả. Trong thời gian ngắn mà năng suất khổng lồ như vậy, việc không lộ danh tính khiến người ta thấy khá thú vị
Nhận định rằng “mọi ngôn ngữ trong 20 năm qua đều thêm sum type, còn Ada thì đã có từ đầu” là đúng, nhưng nguồn gốc của nó không phải từ Ada. Ngôn ngữ Hope hay NPL đã có trước
UNION, sau đó khái niệm này được phát triển trong ALGOL 68, Hope, Miranda, v.v.unioncủa C là một khái niệm khácTôi thích bài này đến mức hy vọng nó không phải do AI viết, nhưng tốc độ đăng trên Twitter quá nhanh nên vẫn thấy đáng nghi
Không quân Mỹ ban đầu định dùng Ada, nhưng do phát triển chậm nên đã dùng JOVIAL. Tôi làm dự án đầu tiên bằng JOVIAL vào năm 1981, khi đó Ada vẫn còn ở giai đoạn đặc tả
Trên trang chủ có câu “đây không phải lập trường mà là đề xuất”, và có người lấy đó làm căn cứ để khẳng định đây là website do AI viết
Bài viết nói rằng “hệ thống module của JavaScript không thể che giấu biểu diễn nội bộ của kiểu như Ada”, nhưng thực ra trong module JS, nếu không export thì hoàn toàn có thể ẩn đi. Vì vậy tôi nghi ngờ Ada có điểm gì vượt trội đặc biệt ở đây