Здравствуйте, Severn, Вы писали:
S>Читай плз внимательнее о чем речь шла. При юнит тесте метода вылетит ассерт, если ассерт покажет UI сообщение, то протестировать метод не получится.
Вы, блин, как маленькие. Это все кастомизируется. Показывать UI сообщение в юнит тесте никто не заставляет — можно просто кинуть исключение или завершить текущий юнит тест еще каким способом
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, minorlogic, Вы писали:
_FR>>Почитал, но ни где не нашёл твоих объяснений своей позиции Только "должно быть так и так", но не почему. В первую очередь мне любопытно: где разница между асертом и исключением?
M>Асерт это ошибка програмиста , исключение это ошибка программы.
Ошибка того, кто написал асерт или того, кто вызвал функцию, в которой асерт произошёл? Именно это мне и интересно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1048>>
Help will always be given at Hogwarts to those who ask for it.
Ужас. А если я всё-таки ошибся и начал передовать в некую библиотеку не правильные данные: представляешь себе, во что обойдётся поиск ошибки в подобной системе? Ведь с таким подходом теряет какой-либо смысл понятие "инварианта" (при условии, что все проверки построены на асертах и в релизе, который имеют пользователи библиотеки они не срабатывают).
Если с библиотекой обращаются не правильно (снабжают недопустимыми данными), она обязана выбросить исключение. Могу допустить, что ритм в этом деле должна задавать стандартная библиотека. Я не могу припомнить во фреймворке (.нет) класс, который вёл бы себя в "защищённом" стиле (если не считать очевидных ошибок в самом фреймворке). И это понятно почему: когда vs рассчитываем на то, что правильность вводимых данных контролирует вызывающий, то:
_FR>Ужас. А если я всё-таки ошибся и начал передовать в некую библиотеку не правильные данные: представляешь себе, во что обойдётся поиск ошибки в подобной системе?
Так не передавай
_FR> Ведь с таким подходом теряет какой-либо смысл понятие "инварианта" (при условии, что все проверки построены на асертах и в релизе, который имеют пользователи библиотеки они не срабатывают).
Ээээ. В смысле?
У тебя есть твоя функция f, которая вызывает библиотечную функцию bf. Если f передает в bf только правильные данные, то проблем не будет ни в дебаге ни в релизе
_FR>Если с библиотекой обращаются не правильно (снабжают недопустимыми данными), она обязана выбросить исключение.
Зачем? В дебаге мы убеждаемся, что передаваемые в библиотеку данные правильные, переключаемся в релиз — и вперед
_FR>Я согласен с Framework Design Guidelines, которая говорит, что _FR>
Good framework design helps the application developer realize the benefits of exceptions.
А я с этим категорически не согласен. Правильный гайдлайн должен быть таким:
Программист должен думать головой, а не надеяться, что в релизе у него вылетит исключение, которое автомагическим способом починит неправильные данные
Здравствуйте, Mamut, Вы писали:
_FR>>Ужас. А если я всё-таки ошибся и начал передовать в некую библиотеку не правильные данные: представляешь себе, во что обойдётся поиск ошибки в подобной системе? M>Так не передавай
Сказать так намного проще, чем заставить несколько десятков человек "делать правильно, так, как нужно".
_FR>> Ведь с таким подходом теряет какой-либо смысл понятие "инварианта" (при условии, что все проверки построены на асертах и в релизе, который имеют пользователи библиотеки они не срабатывают).
M>Ээээ. В смысле?
M>У тебя есть твоя функция f, которая вызывает библиотечную функцию bf. Если f передает в bf только правильные данные, то проблем не будет ни в дебаге ни в релизе
Если bf (пусть это метод класса) не проверяет переданные ей аргументы, считая априори их верными, и пересчитывает на их основании данные класса, то данные класса зависят от того, как вызывать метод. В такой ситуации нельзя гарантировать, что данные класса находятся в согласованном состоянии.
_FR>>Если с библиотекой обращаются не правильно (снабжают недопустимыми данными), она обязана выбросить исключение. M>Зачем? В дебаге мы убеждаемся, что передаваемые в библиотеку данные правильные, переключаемся в релиз — и вперед
Ага, у тебя есть дебажные версии сборок фреймворка, в которых будут срабатывать асерты? А даже если и есть (ой, писал я в этой ветке уже об этом: будто в чёрную дыру говорю ): ну нет в MSVS для .нет-проектов возможности (натуральной, не прикручиваемой сбоку) собирать дебаг моего проекта с дебажными сборками third party, а релиз — с релизными. Я вот сам лично не видел ни одного ассерта от стороннох библиотек, и,судя по сообщениям на форумах, этого не случается ни у кого, видимо потому, что так никто не работает.
_FR>>Я согласен с Framework Design Guidelines, которая говорит, что _FR>>
Good framework design helps the application developer realize the benefits of exceptions.
M>А я с этим категорически не согласен. Правильный гайдлайн должен быть таким:
M>Программист должен думать головой, а не надеяться, что в релизе у него вылетит исключение, которое автомагическим способом починит неправильные данные
Ага, но "думать головой" — более абстрактное требование, которое моджно трактовать так, как захочется. И мы тут говорим не о починке данных. Говорим о диагностике, о сообщении о том, что произошло. При чём тут "починка"?
... << RSDN@Home 1.2.0 alpha 4 rev. 1048>>
Help will always be given at Hogwarts to those who ask for it.
_FR>>>Ужас. А если я всё-таки ошибся и начал передовать в некую библиотеку не правильные данные: представляешь себе, во что обойдётся поиск ошибки в подобной системе? M>>Так не передавай
_FR>Сказать так намного проще, чем заставить несколько десятков человек "делать правильно, так, как нужно".
Ну ведь можно же помечтать
_FR>>> Ведь с таким подходом теряет какой-либо смысл понятие "инварианта" (при условии, что все проверки построены на асертах и в релизе, который имеют пользователи библиотеки они не срабатывают).
M>>Ээээ. В смысле?
M>>У тебя есть твоя функция f, которая вызывает библиотечную функцию bf. Если f передает в bf только правильные данные, то проблем не будет ни в дебаге ни в релизе
_FR>Если bf (пусть это метод класса) не проверяет переданные ей аргументы, считая априори их верными, и пересчитывает на их основании данные класса, то данные класса зависят от того, как вызывать метод. В такой ситуации нельзя гарантировать, что данные класса находятся в согласованном состоянии.
Извращенцы
Вообще в целом, "defensive programming", как и "aggressive programing" просто надо применять там где нужно. Но так хоццы асолюта
Здравствуйте, Mamut, Вы писали:
_FR>>Сказать так намного проще, чем заставить несколько десятков человек "делать правильно, так, как нужно". M>Ну ведь можно же помечтать
Ага, пока не столкнёшся с бездумно натыканными асертами, проверяющими совсем не то, что надо.
M>Вообще в целом, "defensive programming", как и "aggressive programing" просто надо применять там где нужно.
В подобном стиле о чём угодно можно рассуждать :о)
M>Но так хоццы асолюта
Я привык верить, что так не бывает. Не бывает "само по себе", придти к этому можно лишь осуществив вполне определённые шаги, сводящие возможность ошибки к минимому и точно диагностирующие саму ошибку и место её возникновения, но ни как не запрещающие её. Человек имеет право на ошибку, и лишать его это права не честно но можно подсказать, где он не прав, или же помочь избежать ошибки.
... << RSDN@Home 1.2.0 alpha 4 rev. 1048>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, minorlogic, Вы писали:
_FR>>>Почитал, но ни где не нашёл твоих объяснений своей позиции Только "должно быть так и так", но не почему. В первую очередь мне любопытно: где разница между асертом и исключением?
M>>Асерт это ошибка програмиста , исключение это ошибка программы.
_FR>Ошибка того, кто написал асерт или того, кто вызвал функцию, в которой асерт произошёл? Именно это мне и интересно.
Чтобы ответить на этот вопрос необходимо рассмотреть конкретный пример.
Здравствуйте, minorlogic, Вы писали:
>>>Асерт это ошибка програмиста , исключение это ошибка программы. _FR>>Ошибка того, кто написал асерт или того, кто вызвал функцию, в которой асерт произошёл? Именно это мне и интересно. M>Чтобы ответить на этот вопрос необходимо рассмотреть конкретный пример.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, minorlogic, Вы писали:
>>>>Асерт это ошибка програмиста , исключение это ошибка программы. _FR>>>Ошибка того, кто написал асерт или того, кто вызвал функцию, в которой асерт произошёл? Именно это мне и интересно. M>>Чтобы ответить на этот вопрос необходимо рассмотреть конкретный пример.
_FR>Выбирай любой: _FR>
Если код на шарпе то смысла большого не имеет . По любому будет сгенерированно исключение.
Если такое же на плюсах , то во первых можно unsigned использовать , а во вторых , таки да. Лишняя проверка может тормозить и лучше поставить ассерт на входных параметрах.
_FR>
_FR>void Method2() {
_FR> Debug.Assert(!Thread.CurrentThread.IsBackground, "Should be called only from UI thread!");
_FR> Application.Idle += delegate { };
_FR>}
_FR>
В данном случае ассерт оправдан. Во превых если метод вызван из другого потока то это ошибка не программы а програмиста. Во вторых другого способа обеспечить этот контракт вероятно можно не найти.
Да, применение асерта проверяет правильность программы а не данных внутри нее. Таки образом мы проверяем наши внутрениие инварианты класса. Стоит ли использовать "Debug.Assert" или завести свою функциональность , к сожалению не могу сказать. Сильно специфично от библиотек.
Кстати использование асерта на шарпе уже не кажется столь прозрачным как на плюсах , это связанно со спецификой языка.
M>Если код на шарпе то смысла большого не имеет . По любому будет сгенерированно исключение. M>Если такое же на плюсах , то во первых можно unsigned использовать , а во вторых , таки да. Лишняя проверка может тормозить и лучше поставить ассерт на входных параметрах.
Do not create methods that throw NullReferenceException or IndexOutOfRangeException.
(здесь)
. Например, стандартные библиотеки так не делают. Смысл в своей библиотеке делать иначе?
_FR>>void Method2() {
_FR>> Debug.Assert(!Thread.CurrentThread.IsBackground, "Should be called only from UI thread!");
_FR>> Application.Idle += delegate { };
_FR>>}
M>В данном случае ассерт оправдан. Во превых если метод вызван из другого потока то это ошибка не программы а програмиста.
Библиотека — продукт, создаваемый для програмиста (пускай даже сидящего напротив). Список исключений, выбрасываемых методом как раз и скажет програмисту, как надо пользоваться библиотекой. Асерт в таком месте — для лентяев, которые не хотят думать о том, как, где и кем их библиотека может использоваться (вернее, что она может использоваться где угодно, кем угодно и как угодно).
M>Во вторых другого способа обеспечить этот контракт вероятно можно не найти.
А теперь представь себе, что будет в релизе: попросту не будет того, что нужно: у пользователя библиотеки может не быть исходного кода и отладочной версии. И, между прочим, почему бы тут не сделать проверку с исключением? Что бы на if-е съэкономить? Вот уж ни за что не поверю, что это место, требущее оптимизаций.
Вот это красота. На ней моя позиция и основана: если условие зависит от "наружных" данных, то надо делать проверки и бросать исключения. Асерт тут опционален и требует отдельного обсуждения. В том же случае, когда проверки после асерта нет, в релизе получаются чудеса: программа думает, что всё в порядке и пытается хоть как-то работать и падает не там, где должна, а где получится, что усложняет поиск ошибки. Для любого же исключения можно получить номер строки, где оно было вызвано и определить условие возникновения.
Наоборот: ставить исключения в тех местах, которые не зависят от вызывающего кода может показаться странным, так как это будут внутренние детали реализации, и показывать их наружу (а исключения, выбрасываемые методом, есть часть контракта) не есть гуд.
M>Таки образом мы проверяем наши внутрениие инварианты класса.
Разве инвариант — это не данные?
M>Стоит ли использовать "Debug.Assert" или завести свою функциональность , к сожалению не могу сказать. Сильно специфично от библиотек.
Назови хоть одну библиотеку для .нет, логика которой построена на асертах?
M>Кстати использование асерта на шарпе уже не кажется столь прозрачным как на плюсах , это связанно со спецификой языка.
В смысле?
... << RSDN@Home 1.2.0 alpha 4 rev. 1048>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, minorlogic, Вы писали:
Выдавать или нет наружу
NullReferenceException or IndexOutOfRangeException
Не могу оценить . Но вижу причин этого не делать.
_FR>А теперь представь себе, что будет в релизе: попросту не будет того, что нужно: у пользователя библиотеки может не быть исходного кода и отладочной версии. И, между прочим, почему бы тут не сделать проверку с исключением? Что бы на if-е съэкономить? Вот уж ни за что не поверю, что это место, требущее оптимизаций.
Мотивация не делать проверку а использовать ассерт на входные данные может быть изза производительности . Для шарпа это редко бывает решающим фактором. Очевидно что необходимо проверять ВСЕ данные которые приходят извне в библиотеку.
Здравствуйте, minorlogic, Вы писали:
M>Выдавать или нет наружу M>NullReferenceException or IndexOutOfRangeException M>Не могу оценить . Но вижу причин этого не делать.
Отдавать надо ArgumentNullException, либо ArgumentOutOfRangeException. NullReferenceException или IndexOutOfRangeException — это значит разработчик библиотеки пустил неправильные параметры внутрь. NullReferenceException мне ничего не скажет. ArgumentNullException мне скажет о том, что такой-то параметр не может быть null. Аналогично и с *OutOfRangeException.
Здравствуйте, _FRED_, Вы писали:
M>>Асерт это ошибка програмиста , исключение это ошибка программы.
_FR>Ошибка того, кто написал асерт или того, кто вызвал функцию, в которой асерт произошёл? Именно это мне и интересно.
Если нарушены предусловия — виноват вызывающий,
если постусловия — виновата реализация, так как она не смогла выполнить свои обязанности(хотя клиент выполнил свои).
Здравствуйте, Юрий Жмеренецкий, Вы писали:
M>>>Асерт это ошибка програмиста , исключение это ошибка программы. _FR>>Ошибка того, кто написал асерт или того, кто вызвал функцию, в которой асерт произошёл? Именно это мне и интересно. ЮЖ>Если нарушены предусловия — виноват вызывающий,
Конечно, виноват при нарушении предусловий вызывающий. Но почему проверять это нужно асертом, а не бросать исключение?
... << RSDN@Home 1.2.0 alpha 4 rev. 1048>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, Юрий Жмеренецкий, Вы писали:
M>>>>Асерт это ошибка програмиста , исключение это ошибка программы. _FR>>>Ошибка того, кто написал асерт или того, кто вызвал функцию, в которой асерт произошёл? Именно это мне и интересно. ЮЖ>>Если нарушены предусловия — виноват вызывающий,
_FR>Конечно, виноват при нарушении предусловий вызывающий. Но почему проверять это нужно асертом, а не бросать исключение?
Если виноват — должен исправить(проверить явно). Иначе это не предусловие. здесь
Здравствуйте, Odi$$ey, Вы писали:
OE>Здравствуйте, _FRED_, Вы писали:
_FR>> пользователь моих биллиотек, для которого ассерт в _моём_ коде — означает (и правильно!) _мою_ ошибку,
OE>почему правильно-то? всю жизнь, и правильно, assert в коде библиотеки означал, что ее неправильно используют, не так как задумал автор
— зачем-то замаскированная под assert обычная проверка неких условий в runtime, в release и debug — конфигурациях. Я понимаю, что топик длинный и читать его лень, поэтому просто повторю то, что писал про этот вариант здесь
— можно отказаться от assert-ов и поголовно в каждой функции проверять проверять все параметры или другие условия на допустимость и возвращать ошибку или кидать исключение если они некорректны. Но на практике, если я один раз проверил строку введенную пользователем и дальше она путешествует как const по десятку функций — нафига я в каждой функции при выполнении программы буду тратить время на проверку ее формата снова и снова? Лучше я впишу в них assert, который явно обозначит, на что я полагался, когда писал эти функции, при этом в release эта проверка не будет стоить мне ни одного лишнего такта.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
M>>>>>Асерт это ошибка програмиста , исключение это ошибка программы. _FR>>>>Ошибка того, кто написал асерт или того, кто вызвал функцию, в которой асерт произошёл? Именно это мне и интересно. ЮЖ>>>Если нарушены предусловия — виноват вызывающий,
_FR>>Конечно, виноват при нарушении предусловий вызывающий. Но почему проверять это нужно асертом, а не бросать исключение?
ЮЖ>Если виноват — должен исправить(проверить явно). Иначе это не предусловие.
Извини, но ты програмируешь на .NET? Часто нарывался на асерты в сторонних библиотеках? А на ArgumentNullException? Не задумывался, почему для проверки предусловий в стандартных библиотеках используются исключения вместо асертов?
ЮЖ>здесь