Thursday, June 28, 2001

Assertion

Assertion 的使用目的,就是要防止客戶對程式庫的誤用。以 Design by Contract 的原則再加上 OOP 的術語,簡單說來:就是要確保物件在執行操作或行為後還要維持其內部狀態的正確。

假設描述物件這個行為的程式本身正確無誤,而作業系統也沒來找碴,那使物件狀態脫軌的必定來自物件使用者傳入錯誤的引數。

就如同程式行為發生“例外”一樣,程式庫的使用者知道如何偵測錯誤的物件狀態,但卻不知如何處理...

傳統 C 語言的 assert 做法,就是一偵測到要確認的條件不成立了,就立刻終止整個程式的執行,並列印一些偵錯訊息出來。

但是,在這個愈來愈趨向動態的程式世界。有時連客戶都無法確保傳入的引數是正確的,原因可能不是客戶不夠小心,而是在動態的世界裡,這是無法避免的。

這時,在 C++ 中可行的個解法,就是丟出“例外”。被丟出的例外可以被客戶捕捉,並作一些處理措施。萬一客戶不處理,才將程式終結掉。

我這裡使用的,就是裹著 Assertion 的例外,並利用 template 來讓客戶決定要丟出的例外種類:

From: "Jiang Yu-Kwan"
Sent: Monday, June 18, 2001 4:40 PM
Subject: Re: Fw: JavaOne特別報導

我再看了一下,它支援的是 generic programming,而 template 只是在C++下的實作方式。

以 JAVA 設計的哲學,它可能把GP搞得跟 C++ 的 template 語法很像,但骨子裡卻不必preprocessor處理,而是直接在 run time support。

而 assertion 的支援,只是為了支援 Design by Contract ,其支援的完整性,可能更勝 C。

因為 C++ 對 assertion 沒有更進一步的支援(直接沿用C的做法)。所以, JAVA 在這點有很大的改進空間。

以下我就舉例說明一下,如何製造一個 C++ 版本的 assertion 功能:

 1: // assertion.h
 2: //...
 3: 
 4: template <class Exception> void Assert( bool assertion )

 5: {
 6:     if (! assertion) throw Exception();

 7: }
 8: //...
 9: 

經修改後,我現在實際使用的 assertion 版本如下:

1: // Assertion for C++ version.
2: template <class Exception> inline void Assert( bool assertion )

3: {
4: #ifndef NO_CPP_ASSERTION
5:     if (! assertion) throw Exception();

6: #endif
7: }
 1: // user.c
 2: #include "assertion.h"
 3: //...
 4: class Date {

 5: public:
 6:     class Bad_arg{};
 7:     setMonth( int mon );

 8:     //...
 9: private:
10:     //...
11: };
12: 

13: void Date::setMonth( int mon )
14: {

15:     // 確保設定的月數在正確的範圍,否則,
16:     // 就丟出Bad_arg的例外。
17:     Assert<Bad_arg>(1<=mon && mon<=12);

18:     //...
19: }
20: //...
21: 

更進一步的探討可以參考 C++ 之父, Bjarne Stroustrup 所著的 《The C++ Programming Language 3rd Edition》。

0 comments: