Здравствуйте, AVC, Вы писали:
AVC>Я что-то переврал? AVC>В приведенной цитате Макконнелла не содержалось совета использовать утверждения?
AVC>Или я отрицал важность статического контроля типов?
Речь у Сергея о динамических проверках, minorlogic же говорил, что они по смыслу не совпадают с нормальными статическими assert'ами, принятыми в других языках (насколько я это понял).
Ты же привёл как раз цитату о статических проверках, противопоставляя утверждению о них же по сути. AVC>В чем претензия?
Претензия к неправомерности твоей претензии.
Re[17]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, AVC, Вы писали:
AVC>Здравствуйте, Mikhail Polykovsky, Вы писали:
AVC>>>Стыд и позор также Стиву Макконелу за такие вот мысли: AVC>>>
AVC>>>... Старайтесь преобразовывать семантические элементы интерфейса в програм-
AVC>>>мные, используя утверждения (assertions) или иными способами.
MP>>Есть практические рекомендации, как этого достигать? С примерами?
AVC>Да, есть. AVC>См. главы 11 и 12 книги Мейера "Объектно-ориентированное конструирование программных систем". AVC>Там вводится понятие Design By Contract (проектирование по контракту). AVC>А одним из примеров в 12-й главе является как раз функция вычисления квадратного корня sqrt(x).
Статью про контрактное программирование читал. Еще что-нибудь интересное есть? Можете ссылку дать?
Re[18]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, AVC, Вы писали:
AVC>>Я что-то переврал? AVC>>В приведенной цитате Макконнелла не содержалось совета использовать утверждения?
AVC>>Или я отрицал важность статического контроля типов? К>Речь у Сергея о динамических проверках, minorlogic же говорил, что они по смыслу не совпадают с нормальными статическими assert'ами, принятыми в других языках (насколько я это понял). К>Ты же привёл как раз цитату о статических проверках, противопоставляя утверждению о них же по сути. AVC>>В чем претензия? К>Претензия к неправомерности твоей претензии.
Вообще-то говоря, assert (=утверждать) — по определению связан именно с рантаймом.
Утверждение привязано к определенной точке выполнения программы.
Интересно, в каком же это языке иначе сделано?
Во всяком случае — не в Си/Си++.
Другое дело, что иногда компилятор может вычислить значение утверждения (оно константно).
Например, BlackBox отказывается компилировать следующий ASSERT:
ASSERT(SIZE(INTEGER) # 4, 20);
и пишет: ASSERT fault.
Макконнелл же, ИМХО, призывает не оставлять интерфейсные семантические требования только в качестве благих пожеланий в документации, а вводить соответствующие им программные конструкции, например — ASSERT.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[18]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, Mikhail Polykovsky, Вы писали:
MP>Статью про контрактное программирование читал. Еще что-нибудь интересное есть? Можете ссылку дать?
Первое, что приходит в голову — упомянутый Сергеем Губановым BlackBox.
Там принцип программирования по контракту применяется "всерьез".
Вот пример из модуля Math:
PROCEDURE ArcTan2* (y, x: REAL): REAL;
BEGIN
ASSERT((y # 0) OR (x # 0), 20);
ASSERT((ABS(y) # INF) OR (ABS(x) # INF), 21);
FLD(y); FLD(x); FATAN; WAIT; RETURN TOP()
END ArcTan2;
Здесь где-то высказывалась мысль, что математические функции могли бы просто вернуть NaN. Дескать, ничего страшного.
Я с этой мыслью не согласен. (Хотя NaN и лучше, чем ошибочное значение, притворяющееся числом.)
AFAIK, на BlackBox написаны программы, производящие очень сложные и длительные вычисления. Некоторые из этих программ могут требовать нескольких месяцев вычислений. А теперь представьте себе, что Вы дождались и наконец получили долгожданный результат. И читаете: NaN.
Что Вы после этого скажете о программистах, не следующих принципу контрактного программирования?
Конечно, принцип программирования по контракту применяется не только в вычислительных задачах.
Вот другой простой пример: проход по списку. У Вас есть две функции: First и Next.
Предусловием цепочки вызовов Next является предварительный вызов First, инициализирующий итератор и присваивающий ему значение первого элемента в списке или NIL, если список пуст.
И т.д. и т.п.
Если Вас заинтресуют исходные тексты BlackBox (на предмет использования в них design-by-contract), то вот сайт Oberon Microsystems Inc.: http://www.oberon.ch
Но я думаю, что этот принцип должен применяться значительно шире.
Предположу, что имеет смысл покопаться в исходниках стандартных библиотек Си++ и др. языков. Наверняка там обнаружится большое количество исключений, выбрасываемых в случае нарушения контракта клиентом.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, Сергей Губанов, Вы писали:
MS>>А что произойдет если компоненту передать неправильные аргументы? MS>>Идеальный (с моей точки зрения) компонент вернет с помощью того или иного механизма ошибку, а клиент компонента вправе сам решать что ему делать в этом случае — падать или продолжать работать.
Поддерживаю
MS>>Оставляя ASSERT в компоненте программа аварийно завершится по инициативе компонента. MS>>Вы считаете это правильным?
Только если вы автор и клиента и компоненты. Хотя это все равно неправильно.
СГ>Так ведь об этом-то и речь! Против неправильных данных передаваемых внутрь компонента стоит именно ASSERT. Это потому, что в интерфейсе к компоненту чётко прописано какие данные в него передавать можно. В функцию Sqrt можно передавать только неотрицательные числа. В качестве индекса массива можно использовать только число из соответствующего диапазона. Делить на ноль нельзя и т.д. Если программа всё-таки позволяет себе передавать отрицательное число в Sqrt, неправильный индекс массива, собирается разделить на ноль и т.д., то значит программа — ошибочна — получи ассертом по башке и иди ищи ошибку.
Мощно, однако. Особенно, когда речь идет про невизуальные компоненты, работающие в невизуальном клиенте. Типа OLEDB провайдера в MSSQL сервере, обслуживающем промышленную базу данных. Тебе потом за этот assert клиенты такой ... вломят — "мама не горюй"
СГ>ASSERT — оборона одного компонента от других: тот кто собирается не правильно использовать этот компонент — жестоко поплатится за это.
Поплатится тот, кто не понимает разницы между внутренними ошибками компоненты и ошибками, связанными с неправильным использованием.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Кодёнок, Вы писали:
>>> Что должна делать программа марсохода при обнаружении _внутренней >>> ошибки_ на Марсе, когда ASSERT отключен (а ошибка не отключена)?
C>>Перезагружать систему, после N перезагрузок входить в безопасный режим.
Кё>...командировать специалиста...
Шутки — шутками, а один из "ненаших" сторонников Лиспа, насколько я помню, где-то писал про "незабываемые впечатления от использования REPL, работающего где-то там на расстоянии N километров". REPL использовался для отладки/исправления ошибок, естественно.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[15]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, AVC, Вы писали:
M>>3. Стыд разработчикам , что они использовали такое узнаваемое слово как "ASSERT" в ключе отличном от общепринятого.
AVC>Стыд и позор также Стиву Макконелу за такие вот мысли:
AVC>По мере возможности делайте интерфейсы программными, а не семан-
AVC>тическими Каждый интерфейс состоит из программной и семантической
AVC>частей. Первая включает типы данных и другие атрибуты интерфейса, которые могут
AVC>быть проверены компилятором. Вторая складывается из предположений об ис-
AVC>пользовании интерфейса, которые компилятор проверить не может.
AVC> Старайтесь преобразовывать семантические элементы интерфейса в програм-
AVC>мные, используя утверждения (assertions) или иными способами.
Дык надо различать понятие внешних и внутренних интерфейсов.
Во внутренних, в случае ошибки входящих параметров, что хочешь, то и делай — хоть в трубу дуди, хоть приложение терминируй. Ибо это связано с некорректной "внутренней" работой компоненты. Которая, вообще говоря, проверяется во время разработки всякими извращенческими автоматизированными тестами.
А вот параметры внешних интерфейсов, извольте проверять без вот этих крайностей. Поскольку трубу могут не услышать. А за терминирование могут сразу дать по башке. Правильно, не правильно — это потом разбираться будут.
Более того, кто писал компоненты для DCOM, тот обычно прорюхивает еще одно правило внешних интерфейсов — сначало проинициализируй OUT-параметры, а уж потом проверяй IN-параметры и возвращай всякие там коды ошибок.
Кстати еще один замечательный пример — компонент может использоваться в дизайнере. И что — если юзер (ну программер, то есть), указал в инспекторе не то значение — нам всю студию закрывать что ли? Типа "ах ты, негодяй такой, а еще программировать лезешь!"
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[16]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Дык надо различать понятие внешних и внутренних интерфейсов.
Если можно, уточните, что Вы понимаете под внутренними и внешними интерфейсами.
На всякий случай скажу, что принцип проектирования по контракту не применяется к операциям ввода/вывода.
КД>Кстати еще один замечательный пример — компонент может использоваться в дизайнере. И что — если юзер (ну программер, то есть), указал в инспекторе не то значение — нам всю студию закрывать что ли? Типа "ах ты, негодяй такой, а еще программировать лезешь!"
ASSERT не ведет к "терминированию" BlackBox.
Думаю, что и для других программ "терминирование" необязательно.
ИМХО, Сергей Губанов затронул очень серьезную тему: что делать, если обеспечить корректную работу компонента в сложившихся обстоятельствах невозможно.
(Единственное критическое замечание, которое я могу сделать: ИМХО, он слишком много раз употребил выражение "дать по башке". Создается впечатление, что ПО — это война всех против всех, а компонент компоненту — волк. )
Кроме прочих причин невозможности обеспечить корректную работу компонента, назову две.
1) Ограничения реализации. Вам надо получить сумму X и Y, а у Вас случилось переполнение. Такая жалость!
2) Частичные функции. Функция применима не ко всем сочетаниям элементов входных множеств.
Простые примеры:
— sqrt(x) неприменима к случаю x < 0:
— inv(x) = 1/x неприменима к случаю x = 0.
В основном, тема, затронутая Сергеем, относится ко второму случаю.
Подчеркну, что (ИМХО) причина этой ситуации не может быть устранена полностью, т.к. здесь мы упираемся в математический факт. А именно — существование частичных функций.
Думаю, что существует не единственный способ бороться с этой бедой.
Например, на здешних форумах сторонники Си++ не раз приводили примеры классов, гарантирующих некоторые свойства своих объектов. Например, класс реализует указатель и гарантирует, что он — ненулевой.
Я с интересом читаю подобные посты, но мне кажется, что подобный "укрепленный" код не слишком читабелен. (Здесь — жирное ИМХО, конечно.)
На мой взгляд, ASSERT (или другое синтаксическое средство проверки утверждений), проверяющие предусловия подпрограммы (метода) — проще. И потому предпочтительнее в использовании.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[17]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, AVC, Вы писали:
КД>>Дык надо различать понятие внешних и внутренних интерфейсов.
AVC>Если можно, уточните, что Вы понимаете под внутренними и внешними интерфейсами.
Если уточнять на конкретном примере, то COM-интерфейсы — относятся к категории внешних. А интерфейс, например, std::vector — к категории внутренних. По крайней мере — в моей голове именно такое представление об устройстве мира.
AVC>ИМХО, Сергей Губанов затронул очень серьезную тему: что делать, если обеспечить корректную работу компонента в сложившихся обстоятельствах невозможно.
Компонентная технология сама по себе тема серьезная. И компромиссы с реальной практикой здесь играют не последнюю роль.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[15]: Sqrt - хороший пример компонента обороняющегося от о
AVC>Стыд и позор также Стиву Макконелу за такие вот мысли:
Да,нет , наоборот . Все вроде нормально сказанно. В чем вы увидели недостаток этого кучка текста ? И главное где там и что про асерты в релизе говорится ?
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[19]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, AVC, Вы писали:
AVC>Здравствуйте, Курилка, Вы писали:
К>>Претензия к неправомерности твоей претензии.
AVC>Вообще-то говоря, assert (=утверждать) — по определению связан именно с рантаймом.
На основаниии чего ты такое утверждаешь?
Чем утверждение времени компиляции не утверждение?
Прочитай ещё раз приведённую тобой цитату и покажи — где там рантайм есть? (про компилятор я тебе уже показывал)
Re[15]: Sqrt - хороший пример компонента обороняющегося от о
Кратко о C/C++:
Assert — с которым я знаком это элемент контроля ошибок ПРОГРАММИСТА а не программы.
У программы есть свои методы контроля, исключения к примеру, коды ошибок.
И большая неразбериха возникнет если путать инструменты и использовать их не по назначению.
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Поплатится тот, кто не понимает разницы между внутренними ошибками компоненты и ошибками, связанными с неправильным использованием.
Ваша мысль в той или иной форме здесь уже многократно высказывалась. И я на неё уже отвечал (в той или иной форме). Потрудитесь сначала прочитывать все сообщения...
Re[19]: Sqrt - хороший пример компонента обороняющегося от о
AVC>Здесь где-то высказывалась мысль, что математические функции могли бы просто вернуть NaN. Дескать, ничего страшного. AVC>Я с этой мыслью не согласен. (Хотя NaN и лучше, чем ошибочное значение, притворяющееся числом.) AVC>AFAIK, на BlackBox написаны программы, производящие очень сложные и длительные вычисления. Некоторые из этих программ могут требовать нескольких месяцев вычислений. А теперь представьте себе, что Вы дождались и наконец получили долгожданный результат. И читаете: NaN.
Если в документации к Sqrt написано, что в случае ошибки она вертает NaN, а вы никогда результат не проверяете, то виноваты будете именно вы.
Re[20]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, MShura, Вы писали:
AVC>>Здесь где-то высказывалась мысль, что математические функции могли бы просто вернуть NaN. Дескать, ничего страшного. AVC>>Я с этой мыслью не согласен. (Хотя NaN и лучше, чем ошибочное значение, притворяющееся числом.) AVC>>AFAIK, на BlackBox написаны программы, производящие очень сложные и длительные вычисления. Некоторые из этих программ могут требовать нескольких месяцев вычислений. А теперь представьте себе, что Вы дождались и наконец получили долгожданный результат. И читаете: NaN. MS>Если в документации к Sqrt написано, что в случае ошибки она вертает NaN, а вы никогда результат не проверяете, то виноваты будете именно вы.
Совершенно согласен.
Допустим, я всегда проверяю значение, возвращаемое функцией sqrt, на предмет, является ли оно числом.
Значит ли это, что теперь я могу спокойно "подсовывать" этой функции отрицательный аргумент, не утруждая себя проверкой его на неотрицательность?
И разве следующий код
y = sqrt(x);
if (IsNaN(y)) { ... }
лучше, чем
if (x >= 0.0)
у = sqrt(x);
else { ... }
?
(Разумеется, есть куча ситуаций, когда необходимо проверять возврат функции: открытие файла, запрос памяти в куче с помощью malloc etc. Но есть ситуации, где клиенту надо проверить корректность аргументов вызываемой функции. О них и идет речь.)
Клиент должен отвечать не только за корректность аргументов вызываемых функций, но и за
— корректность значения индекса элемента массива;
— предотвращение переполнения при выполнении арифметической операции;
— корректное (например — ненулевое) значение указателя и т.д и т.п.
Во всех этих случаях не предусмотрено специального значения "ошибка", а происходит исключение (в лучшем случае) или ошибка остается незамеченной, что можно привести к непредсказуемым последствиям (в худшем).
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[20]: Sqrt - хороший пример компонента обороняющегося от о
Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, AVC, Вы писали:
AVC>>Здравствуйте, Курилка, Вы писали:
К>>>Претензия к неправомерности твоей претензии.
AVC>>Вообще-то говоря, assert (=утверждать) — по определению связан именно с рантаймом. К>На основаниии чего ты такое утверждаешь?
На основании того, что есть такое понятие — мониторинг утверждений.
И того, что assert() в Си/Си++ в случае невыполнения утверждения вызывает abort().
Вызывать abort() необязательно (это крайность), но согласись, что вызов abort() имеет смысл только для рантайма.
Не компилятор же будет терминироваться.
К>Чем утверждение времени компиляции не утверждение?
Частный (вырожденный) случай утверждения.
К>Прочитай ещё раз приведённую тобой цитату и покажи — где там рантайм есть? (про компилятор я тебе уже показывал)
Покажи, где его там нет.
Приведи пример осмысленного использования assertion в твоем понимании.
Вот Сергей Губанов привел такой пример:
PROCEDURE Sqrt(x: REAL): REAL;
BEGIN
ASSERT(x >= 0.0, 20);
Хороший это пример или плохой, наверное, можно спорить.
Но он осмысленный.
А вот вы на пару с minorlogic пока кроме особо изысканного
assert(sizeof(int) == 32); /* почему именно 32, я не понял */
ничего путного пока не предложили (имхо, конечно ).
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, 0rc, Вы писали:
0rc>А если ASSERT включен на Марсе, что тогда, легче будет?
Ещё бы! Сейчас не те времена! Залезаем на марсоход через терминалку и жмем "Ignore". А если писать код на интерпретаторе или на языке поддерживющем модификаци кода без перекомпиляции, то ваще жмем "Retry" и правим код!
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Какие люди в Голиваде?
AF>ASSERT проверяет условие, которое истинно всегда. Если вы уже знаете, что вы не контролируете входные данные и они могут быть недействительными, то ASSERT, очевидно, для этого не подходит. Вместо этого там должна быть полноценная проверка аргументов, с возвратом кодов ошибок, выбрасыванием исключений, и т.д, и все это является частью интерфейса вашего компонента.
А может пусть компилятор выкидывает проверки не имеющие смысла и выносит их из критичных мест повыше? А мы просто всегда будем с "выбрасыванием исключений" жить?
Не, ну, кто гарантирует, что тот же выход за пределы массива не возникнет именно в релизе?
AF>С другой стороны, если я в release версии своего компонента оставлю все ASSERTs, и в один прекрасный момент вы обнаружите, что срабатывает ASSERT где-то на двенадцатом уровне вызовов, чем вам это поможет?
Исключине поможет всегда.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, AVC, Вы писали:
Д>>про это еще Страуструп говорил Д>>примененять защитные проверки в debug конфигурации и отключать их в release — это всё равно что плавать на корабле с полным набором спасательных кругов и шлюпок возле берега, и сгружать их на берег перех выходом в открытое море.
AVC>Да-да, еще Страуструп. AVC>А до Страуструпа — еще Хоар.
Ага. Еще царь такой то в таком то году говаривал "я вас баяре на сквозь вижу я вас бояре...". Так что и шлюпки тоже на нас запишите, плиз.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.