Procedural Programming + Ada, Bài 3 – Các Cú Pháp Imperative

Tram Ho

Để tiện cho việc tạo và quản lý các tệp code rời cho mỗi ví dụ, chúng ta sẽ thiết lập project và sử dụng trình gprbuild thay cho trình biên dịch gnatmake. Ở đây mình sẽ tạo một thư mục có tên là learn-ada trong Documents với cấu trúc như sau:

Tệp learn_ada.gpr là một dạng khai báo giống như package.json của các project trên nền NodeJS, tuy nhiên có cấu trúc đơn giản hơn khá nhiều:

  • Chúng ta có các ngôn ngữ có thể được sử dụng trong projectadac.
  • Tất cả các thư mục chứa code mà chúng ta viết sẽ được đặt trong thư mục src.
  • Chương trình sẽ bắt đầu từ tệp main.adb đặt ở cấp đầu tiên ngay trong thư mục src.
  • Các dòng comment ví dụ cho việc khai báo sử dụng thêm một thư viện mà chúng ta viết đã biên dịch thành các tệp thực thi, bao gồm: tên thư mục, tên thư viện, kiểu thư viện đã biên dịch được gọi là Dynamic.
  • Thư mục chứa các tệp thực thi sau khi biên dịch xong là obj.

Bây giờ chúng ta cần copy/paste lại code của chương trình Hello World:

Trong cửa sổ dòng lệnh, di chuyển tới thư mục làm việc là Documents/learn-ada.

Sau đó chạy lệnh biên dịch bằng trình quản lý dự án gprbuild và tiếp tục chạy tệp thực thi main được gprbuild tạo ra trong thư mục obj.

Thao tác chạy lệnh biên dịch và tệp main sẽ cố định thế này bởi vì chúng ta đã thiết lập tệp gpr để tự tìm tất cả các tệp code trong thư mục src. Trong các ví dụ từ đây trở về sau thì mình sẽ chỉ copy/paste kết quả chạy tệp main để giảm bớt các thao tác lặp không cần thiết. Và bây giờ thì chúng ta sẽ điểm danh qua tất cả các cú pháp imperative phổ biến.

Khai Báo Biến

Mở đầu là thao tác khai báo biến và phép gán giá trị. Chúng ta có tên các biến được đặt theo dạng thức của các sub-program và các package, với chữ cái đầu tiên của mỗi từ viết hoa và các từ được nối với nhau bởi dấu gạch chân _.

Cú pháp định kiểu dữ liệu cho biến của Ada là dạng mô tả hậu tố giống với Scala, TypeScript, Kotlin, v.v… Theo sau tên biến là : Tên_Kiểu_Dữ_Liệu. Và thao tác gán sử dụng ký hiệu := giống với SQL thay vì ký hiệu = như phần lớn các ngôn ngữ khác.

Do hiện tại chúng ta chưa chạm tới các thư viện tiêu chuẩn nên sẽ tạm ghi nhớ thao tác nối chuỗi là &. Kèm theo đó là thao tác chuyển số nguyên N sang kiểu chuỗi là Integer'Image (N). So với C thì phần khai báo biến được Ada quy định khu vực riêng bằng cấu trúc của cú pháp. Còn khi viết chương trình trong C thì thói quen của các dev giỏi truyền lại là nên tập trung khai báo trong các dòng đầu tiên của các sub-program.

If .. Then .. Else

Cú pháp if .. else nối tiếp của Ada cũng rất thân thuộc so với các ngôn ngữ Imperative khác. Ở đây chúng ta có từ then được sử dụng để kết thúc biểu thức xét điều kiện và ở đoạn nối tiếp else if được viết gộp thành elsif theo phiên âm.

Nhân tiện thì chúng ta học được thêm thao tác in chuỗi không ngắt dòng Put (String) và thao tác Get (N) để đọc kết quả nhập liệu của người dùng và ghi vào biến N. Các phép kiểm tra điều kiện được sử dụng trong ví dụ bao gồm:

  • Kiểm tra nhận định giá trị tương đương =.
  • Từ khóa or tương đương với ký hiệu || trong CJavaScript mà chúng ta đã biết.
  • Phép kiểm tra in để xét phần tử thuộc một tập hợp các giá trị nào đó.

Thực sự là nếu xét trên tiêu chí giao diện lập trình bậc cao thì Ada thân thiện hơn so với C rất nhiều. Nếu bạn để ý thì các thủ tục có sẵn của Ada đều có tên rất rõ ràng và đầy đủ chứ không viết tắt như các sub-program trong thư viện tiêu chuẩn của C. Ví dụ như trình chuyển kiểu bất kỳ sang kiểu số nguyên của C được đặt tên là atoi() – nếu được hiểu đầy đủ thì là any_to_integer.

Câu chuyện nằm ở chỗ là trình biên dịch của C sẽ không tự động tối ưu tệp mã nguồn mà chúng ta viết ra. Chính vì vậy nên khi C được thiết kế khởi điểm để giao tiếp ở cấp độ tiếp giáp với các tài nguyên của hệ thống low-level programming, người ta luôn cố gắng tối giản các tên định danh trong thao tác đặt tên các biến và các sub-program. Có lẽ vì vậy nên C mạnh mẽ nhưng việc sử dụng C cho các ứng dụng phổ thông lại rất nhọc nhằn so với các ngôn ngữ lập trình bậc cao. Và Ada, có lẽ là được tạo ra để hoàn thiện C ở khía cạnh này.

Case .. When

Thay vì switch .. case thì chúng ta có case .. when rất tương đồng với SQL:

Oh.. phép thực thi or trong cú pháp này được thay bằng ký hiệu |. Mình đã thử sử dụng ký hiệu này vào lại vị trí của or trong cú pháp if .. else thì thấy báo lỗi. Đây là điểm mà chúng ta có thể cần phải ghi nhớ ngay và luôn.

Ternary Operator

Ngoài các cấu trúc lệnh rẽ nhánh thì trong CJavaScript chúng ta còn biểu thức điều kiện Ternary Operator để kiểm tra một điều kiện và chọn giá trị gán cho biến.

Nếu first > second thì chọn first để gán vào which, nếu không thì chọn second. Và trong một số ngôn ngữ khác thì các ký hiệu ?: sẽ được thay bằng các từ khóa mang ý nghĩa rõ ràng hơn. Mà nếu vậy thì Ada chắc chắn là sẽ sử dụng các từ khóa, ở bài trước họ giới thiệu rõ ràng vậy rồi mà.

Ngôn ngữ Elm được giới thiệu trong Sub-Series trước đó cũng có biểu thức điều kiện if .. else tương tự. Tuy nhiên, điểm khác biệt là trong Ada chúng ta sẽ cần sử dụng một cặp ngoặc đơn () để khoanh vùng biểu thức này. Có lẽ là vì để dễ tách thông tin khi đọc một câu lệnh dài với các yếu tố được cách đều bằng một khoảng trống.

Các Vòng Lặp

So với các ngôn ngữ Imperative phổ biến thì Ada không có cú pháp do .. while, mà thay vào đó thì có vòng lặp đơn thuần bare-loop không giới hạn số lần lặp. Ở đây chúng ta sẽ phải chèn một câu lệnh kiểm tra điều kiện và thoát khỏi vòng lặp vào một số điểm cần thiết:

  • loop – từ khóa mở đầu vòng lặp
  • exit when .. ; – câu lệnh kiểm tra điều kiện thoát khỏi vòng lặp
  • end loop; – từ khóa kết thúc vòng lặp

Cú pháp vòng lặp for .. in có cách thức hoạt động khá giống với các cú pháp for .. in/of của JavaScript.

Và cú pháp vòng lặp while cũng rất thân thuộc.

Tiếp theo chúng ta sẽ nói về các sub-program..

(chưa đăng tải) Procedural Programming + Ada, Bài 4 – Package & Sub-Program

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo