例如,我必須確保某個實時系統的某個功能在20 ms或更短的時間內工作。我可以簡單地在一個函數的開始和結束時測量時間,然後聲明差異是令人滿意的。我在C++中這樣做。如何組織使用D契約的時間不變檢查?
但是,這看起來很像合同,除了時間檢查是一個後置條件,並且開始時的時間測量根本不是條件。把它放入合同不僅是爲了它的標記,而且也是爲了建立理由。
所以我想知道,我可以使用契約功能來檢查功能工作的時間嗎?
例如,我必須確保某個實時系統的某個功能在20 ms或更短的時間內工作。我可以簡單地在一個函數的開始和結束時測量時間,然後聲明差異是令人滿意的。我在C++中這樣做。如何組織使用D契約的時間不變檢查?
但是,這看起來很像合同,除了時間檢查是一個後置條件,並且開始時的時間測量根本不是條件。把它放入合同不僅是爲了它的標記,而且也是爲了建立理由。
所以我想知道,我可以使用契約功能來檢查功能工作的時間嗎?
排序,但不是很好。原因是in {}塊中聲明的變量在out {}塊中不可見。 (有過一些討論要改變這一點,所以它可以在塊進行復印在檢查前VS後的狀態,但什麼也沒有實現)。
所以,這將不工作:
void foo()
in { auto before = Clock.currTime(); }
out { assert(Clock.currTime - before < dur!"msecs"(20)); }
body { ... }
來自in的變量不會結轉出來,給你一個未定義的標識符錯誤。但是,我說「有點」,因爲有一個潛在的解決方法:
import std.datetime;
struct Foo {
SysTime test_before;
void test()
in {
test_before = Clock.currTime();
}
out {
assert(Clock.currTime - test_before < dur!"msecs"(20));
}
body {
}
}
聲明該變量爲結構的常規成員。但是這意味着每個函數都會有很多其他無用的變量,它們不適用於遞歸,並且會污染成員名稱空間。
我的一部分認爲你可以將自己的堆棧放在一邊,並在{}推送時間,然後{}彈出它並檢查....但快速測試顯示它很容易一旦繼承受到影響就會中斷。如果您每次都在{}塊中重複該操作,則可能會起作用。但這讓我感覺非常脆弱。具有合同繼承的規則是需要通過繼承樹的所有out {}塊,但只有任何一個in {}塊需要通過。所以如果你在鏈中有不同的東西,它可能會忘記推遲時間,然後當你試圖彈出時,你的堆棧會下溢。
// just for experimenting.....
SysTime[] timeStack; // WARNING: use a real stack here in production, a plain array will waste a *lot* of time reallocating as you push and pop on to it
class Foo {
void test()
in {
timeStack ~= Clock.currTime();
}
out {
auto start = timeStack[$-1];
timeStack = timeStack[0 .. $-1];
assert(Clock.currTime - start < dur!"msecs"(20));
import std.stdio;
// making sure the stack length is still sane
writeln("stack length ", timeStack.length);
}
body { }
}
class Bar : Foo {
override void test()
in {
// had to repeat the in block on the child class for this to work at all
timeStack ~= Clock.currTime();
}
body {
import core.thread;
Thread.sleep(10.msecs); // bump that up to force a failure, ensuring the test is actually run
}
}
這似乎工作,但我認爲這是比它的價值更麻煩。我希望隨着程序變得更大,它會以某種方式打破,如果你的測試打破了你的程序,那麼這個目標就會失敗。
如果只使用顯式測試檢查滿足您的需求(但請注意,如果您使用-release開關進行編譯,那麼像D中大多數斷言那樣的合約將被刪除,所以我可能會將其作爲unittest {}如果你需要它可靠地失敗,拋出一個異常而不是斷言,因爲在調試和發佈模式下,它總能工作。)。
或者你可以在函數或輔助結構體中使用assert或類似於C++的方法來做到這一點。我會使用一個範圍後衛:
void test() {
auto before = Clock.currTime();
scope(exit) assert(Clock.currTime - before < dur!"msecs"(20)); // or import std.exception; and use enforce instead of assert if you want it in release builds too
/* write the rest of your function */
}
當然,在這裏你必須給它的子類太複製,但它似乎是你必須做的是與在{}塊,無論如何,所以,以及至少前面的變量是本地的。底線,我想說你可能最好的做法或多或少像C++一樣。