Мне трудно выбрать, следует ли мне «принудительно применять» условие или «утверждать» условие в D. (Однако это не зависит от языка.)
Теоретически я знаю, что вы используете утверждения для поиска ошибок и применяете другие условия для проверки нетипичных условий. Например. вы могли бы сказать assert(count >= 0)
в качестве аргумента вашего метода, потому что это указывает на то, что в вызывающей программе есть ошибка, и что вы бы сказали enforce(isNetworkConnected)
, потому что это не ошибка, это просто то, что вы предполагаете, что вполне может быть неправдой в законной ситуации вне вашего контроля.
Кроме того, утверждения могут быть удалены из кода в качестве оптимизации без побочных эффектов, но ограничения нельзя удалить, поскольку они должны всегда выполнять свой код условия. Следовательно, если я реализую контейнер с ленивым заполнением, который заполняется при первом обращении к любому из его методов, я говорю enforce(!empty())
вместо assert(!empty())
, потому что проверка на empty()
должна происходить всегда, так как он лениво выполняет код внутри.
Так что я думаю, что знаю, что они должны означать. Но теория легче практики, и мне трудно применять концепции.
Рассмотрим следующее:
Я создаю диапазон (похожий на итератор), который перебирает два других диапазона и добавляет результаты. (Для функциональных программистов: я знаю, что вместо этого я могу использовать map!("a + b")
, но пока игнорирую это, так как это не иллюстрирует вопрос.) Итак, у меня есть код, который выглядит так в псевдокоде:
void add(Range range1, Range range2)
{
Range result;
while (!range1.empty)
{
assert(!range2.empty); //Should this be an assertion or enforcement?
result += range1.front + range2.front;
range1.popFront();
range2.popFront();
}
}
Это должно быть утверждением или принуждением? (Является ли вина вызывающей стороны в том, что диапазоны не опустошаются одновременно? Возможно, он не имеет контроля над тем, откуда был взят диапазон — он мог быть получен от пользователя — но опять же, он по-прежнему выглядит как ошибка, не так ли?)
Или вот еще пример псевдокода:
uint getFileSize(string path)
{
HANDLE hFile = CreateFile(path, ...);
assert(hFile != INVALID_HANDLE_VALUE); //Assertion or enforcement?
return GetFileSize(hFile); //and close the handle, obviously
}
...
Должно ли это быть утверждением или принуждением? Путь может исходить от пользователя, так что это может не быть ошибкой, но предварительным условием этого метода по-прежнему является правильность пути. Я утверждаю или принуждаю?
Спасибо!