Я не уверен, что он полностью независим от языка. Ни один язык, который я использую , не имеет enforce()
, и если бы я столкнулся с тем, который использовал, то я бы хотел использовать assert
и enforce
так, как они были предназначены, что может быть идиоматичным для этого языка .
Например, assert
в C или C ++ останавливает программу в случае сбоя, не выдает исключение, поэтому его использование может отличаться от того, о чем вы говорите. Вы не используете assert
в C ++, если только вы не думаете, что либо вызывающий объект уже допустил ошибку настолько серьезную, что на нее нельзя полагаться при очистке (например, передавая отрицательное число), либо другой код в другом месте допустил настолько серьезную ошибку, что считается, что программа находится в неопределенном состоянии (например, ваша структура данных выглядит поврежденной). C ++ действительно различает ошибки времени выполнения и логические ошибки, которые могут приблизительно соответствовать, но я думаю, что в основном это ошибки, которых можно избежать, а не ошибки, которые можно избежать.
В случае add
вы бы использовали логическую ошибку, если намерение автора состоит в том, что программа, предоставляющая несоответствующие списки, содержит ошибки и нуждается в исправлении, или исключение времени выполнения, если это только одна из тех вещей, которые могут произойти. Например, если бы ваша функция работала с произвольными генераторами, которые не обязательно должны сообщать об их длине, не деструктивно оценивая всю последовательность, вы, скорее всего, сочтете это неизбежным условием ошибки.
Называя это логической ошибкой, подразумевается, что вызывающий абонент обязан проверить длину перед вызовом add
, если они не могут убедиться в этом по чистой причине. Таким образом, они не будут передавать список от пользователя без предварительной явной проверки длины, и, честно говоря, должны считать себя счастливчиками, что они даже получили исключение, а не неопределенное поведение.
Называя ее ошибкой во время выполнения, выражается, что «разумно» (если она ненормальная) передавать списки различной длины, за исключением того, что это произошло в этом случае. Поэтому я думаю, что это скорее принуждение, чем утверждение.
В случае filesize
: для существования файла вы должны, если возможно, рассматривать это как потенциально исправимый сбой (принудительное применение), а не как ошибку (утверждение). Причина в том, что вызывающий не может быть уверен, что файл существует - всегда найдется кто-то с большими привилегиями, который может прийти и удалить его, или размонтировать всю файловую систему, между проверкой существования и вызовом filesize
. Следовательно, это необязательно логический недостаток вызывающего кода, когда он не существует (хотя конечный пользователь мог выстрелить себе в ногу). Из-за этого факта, вероятно, будут абоненты, которые могут рассматривать это как одну из тех вещей, которые происходят, неизбежное состояние ошибки. Создание дескриптора файла также может не работать из-за нехватки памяти, что является еще одной неизбежной ошибкой в большинстве систем, хотя и не обязательно, что ее можно исправить, если, например, включена избыточная фиксация.
Другой пример, который нужно рассмотреть, это operator[]
против at()
для вектора C ++. at()
выдает out_of_range
, логическую ошибку не потому, что вызывающий абонент может не захотеть восстановиться, или потому, что вы должны быть каким-то тупиком, чтобы совершить ошибку при доступе к массиву вне диапазона, используя at()
, но поскольку ошибки можно избежать, если вызывающая сторона хочет, чтобы она была - вы всегда можете проверить size()
перед доступом, если у вас нет другого способа узнать, хорош ваш индекс или нет. И поэтому operator[]
вообще не гарантирует никаких проверок, и во имя эффективности доступ вне диапазона имеет неопределенное поведение.