- vừa được xem lúc

[Procedural Programming + Ada] Bài 13 - Contracts & Exceptions

0 0 13

Người đăng: Semi Dev

Theo Viblo Asia

Cấu hình ngôn ngữ của Ada có hỗ trợ một dạng thiết kế có tên là Design by Contract - có thể được hiểu là thiết kế phần mềm dựa trên các điều kiện ràng buộc đối với dòng dữ liệu trao đổi giữa các sub-program. Thuật ngữ này được giới thiệu lần đầu bởi giáo sư Bertrand Meyer khi trình bày về nguyên lý thiết kế của ngôn ngữ lập trình Eiffel do chính ông tạo ra.

Trong bối cảnh của Eiffel - là một ngôn ngữ lập trình hướng đối tượng OOP - các thỏa thuận contract xuất hiện với vai trò là các điều kiện ràng buộc căn bản trong tương tác giữa các object. Ý tưởng này xuất phát từ các giao dịch thương mại trong cuộc sống hàng ngày của chúng ta, khi mà các bên tham gia đều phải xác nhận sự đồng thuận trên các bản hợp đồng giao dịch.

Và trong Ada, nguyên lý DbC căn bản được biểu thị bởi các yếu tố:

  • Các ràng buộc contract trước pre và sau post tương tác - áp dụng cho các sub-program.
  • Các ràng buộc contract định kiểu predicate - giống với prepost nhưng áp dụng cho các type.
  • Các ràng buộc contract định kiểu invariant - giống với predicate nhưng áp dụng cho các kiểu định nghĩa private.

Pre & Post

Các ràng buộc contract trước pre và sau post được sử dụng để mô tả dự kiến đối với các tham số và giá trị trả về của các sub-program.

with Ada.Text_IO; use Ada.Text_IO; procedure Main is Result : Integer; procedure Do_Something ( Input : in Integer ; Output : out Integer ) with Pre => (Input > 0) , Post => (Output < 9) is begin -- Do_Something Output := 9; end Do_Something;
begin -- Main Result := 9; Do_Something (0, Result); Put_Line (Integer'Image (Result));
end Main;

Trong code ví dụ ở trên, chúng ta có procedure Do_Something với khối contract được chỉ định bởi các khóa with theo sau đó là các vế điều kiện PrePost. Và ở phần code sử dụng Do_Something, chúng ta đã truyền các giá trị vào các tham số tương ứng là Input = 0Ouput = 9 đều không hợp lệ với các contract. Để các tính năng DbC có thể hoạt động thì chúng ta cần chỉ định cho trình biên dịch kích hoạt chế độ kiểm tra assertion bằng tham số -gnata.

gprbuild -gnat2020 -gnata learn_ada.gpr

Do chế độ assertion là các yếu tố kiểm tra sẽ được áp dụng tại thời điểm runtime để tạo ra các Exception phù hợp. Vì vậy nên chúng ta sẽ không thấy gnat thông báo lỗi trong tiến trình biên dịch.

cd obj && main && cd .. raised ADA.ASSERTIONS.ASSERTION_ERROR : failed precondition from main.adb:...

Như vậy là chương trình sẽ dừng hoạt động ngay khi thao tác kiểm tra tại Pre tạo ra Exception. Bạn có thể chỉnh sửa lại code ví dụ để kiểm tra hoạt động của vế điều kiện Post nếu muốn. Kết quả thông báo lỗi sẽ không có gì khác biệt nhiều.

raised ADA.ASSERTIONS.ASSERTION_ERROR : failed postcondition from main.adb:...

Đối với các hàm function thì kết quả được trả về không thông qua tham số nào và vì vậy nên Ada có cung cấp thuộc tính Function'Result để hỗ trợ mô tả Post contract.

function Triple (Value : Integer) return Integer
with Pre => (Value > 0) , Post => (Triple'Result < 100)
is Result : Integer;
begin -- Triple Result := Value * 3; return Result;
end Triple;

Predicates

Các vế điều kiện PrePost chỉ có hiệu lực khi các sub-program được vận hành thực tế. Vì vậy nên các công cụ này sẽ chỉ thể hiện các Exception tại run-time. Tuy nhiên, các Predicate áp dụng cho các type lại có thêm khả năng kiểm tra tại thời điểm biên dịch code. Cụ thể là chúng ta có 2 loại Predicate:

  • Static_Predicate - kiểm tra các đối tượng dữ liệu ở thời điểm biên dịch compile-time. Ví dụ như các hằng số được định nghĩa bởi các thư viện bên ngoài mà chúng ta muốn tích hợp vào project.
  • Dynamic_Predicate - kiểm tra các đối tượng dữ liệu ở thời điểm vận hành run-time.

Về cú pháp sử dụng thì chúng ta vẫn sẽ sử dụng từ khóa with để liệt kê các vế Predicate giống với khi viết các vế PrePost. Tuy nhiên, khối contract lúc này được đặt cố định ở cuối code định nghĩa type hoặc subtype.

type Course is record Name : Unbounded_String; Start_Date : Date; End_Date : Date;
end record
with Dynamic_Predicate => (Course.Start_Date < Course.End_Date);

Lưu ý ở đây là các Predicate chỉ hỗ trợ các typesubtype được cung cấp định nghĩa public. Trong trường hợp cần sử dụng tính năng đóng gói Type Encapsulation đã được giới thiệu trước đó, bạn có thể tham khảo thêm tài liệu về Type_Invariant tại đây - learn.adacore.com.

Exceptions

Như vậy là chúng ta đã biết thêm những công cụ hỗ trợ kiểm tra kết quả vận hành của code mà không cần phải viết Unit Test. Khi đã có thể tạo ra những Exception mô tả các trường hợp ngoại lệ, công cụ tiếp theo mà chúng ta cần tìm hiểu là cú pháp xử lý ngoại lệ của Ada.

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions; procedure Main is Type_Exception : exception; Value_Exception : exception;
begin -- Main raise Value_Exception with "Message of Value_Exception"; -- maybe ... -- long ... -- code ... exception when Exc : Type_Exception => Put_Line ("Invalid Type"); when Exc : Value_Exception => Put_Line (Exception_Message (Exc));
end Main;

Trong code ví dụ ở trên, chúng ta đã tự định nghĩa các kiểu Type_ExceptionValue_Exception. Sau đó phát động một sự kiện ngoại lệ với kiểu Value_Exception. Các sự kiện ngoại lệ sẽ được chuyển tiếp từ nơi được phát động cho tới các khối block tham chiếu từ bên ngoài, cho đến khi tìm thấy trong phạm vi của một block nào đó có một khối xử lý ngoại lệ exception như trên.

Trong trường hợp một ngoại lệ đã được phát động và chuyển tiếp cho tới khối code tại Main và vẫn không tìm thấy khối xử lý ngoại lệ nào thì chương trình sẽ dừng hoạt động tại vị trí câu lệnh phát động sự kiện ngoại lệ.

[Procedural Programming + Ada] Bài 14 - Multi-Tasking & Protected Types

Bình luận

Bài viết tương tự

- vừa được xem lúc

Closure trong Javascript - Phần 2: Định nghĩa và cách dùng

Các bạn có thể đọc qua phần 1 ở đây. Để mọi người không quên, mình xin tóm tắt gọn lại khái niệm lexical environment:.

0 0 66

- vừa được xem lúc

Var vs let vs const? Các cách khai báo biến và hằng trong Javascript

Dạo này mình tập tành học Javascript, thấy có 2 cách khai báo biến khác nhau nên đã tìm tòi sự khác biệt. Nay xin đăng lên đây để mọi người đọc xong hy vọng phân biệt được giữa let và var, và sau đó là khai báo hằng bằng const.

0 0 47

- vừa được xem lúc

VueJS: Tính năng Mixins

Chào mọi người, hôm nay mình sẽ viết về Mixins và 1 số vấn đề trong sử dụng Mixins hay ho mà mình gặp trong dự án thực. Trích dẫn từ trang chủ của VueJS:.

0 0 41

- vừa được xem lúc

Asset Pipeline là cái chi chi?

Asset Pipeline. Asset pipeline là cái chi chi. . Giải thích:.

0 0 74

- vừa được xem lúc

Tạo data table web app lấy dữ liệu từ Google Sheets sử dụng Apps Script

Google Sheets là công cụ tuyệt vời để lưu trữ bảng tính trực tuyến, bạn có thể truy cập bảng tính bất kỳ lúc nào ở bất kỳ đâu và luôn sẵn sàng để chia sẻ với người khác. Bài này gồm 2 phần.

0 0 280

- vừa được xem lúc

Học Deep Learning trên Coursera miễn phí

Bạn muốn bắt đầu với Deep Learning nhưng không biết bắt đầu từ đâu? Bạn muốn có một công việc ở mức fresher về Deep Learning? Bạn muốn khoe bạn bè về kiến thức Deep Learning của mình. Bắt đầu từ đâu.

0 0 50