Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Юрий Жмеренецкий, Вы писали:
E>>>Вам бы хотелось разбираться с падением банковской системы, которая должна работать в режиме 24x7 под нагрузкой в несколько тысяч транзакций в секунду из-за того, что месяц назад при некорректном использовании max_element был испорчен какой-то байтик в памяти? ЮЖ>>Вот почему-то все думают что если я использую nothrow версию, то я не проверяю параметры...
E>Вы может и проверяете. Я не всегда проверяю.
Я не говорю о том чтобы проверять всегда.
ЮЖ>>Разыменование невалидного итератора — эта ситуация которой не может быть вообще. Исходя из пост и предусловий можно доказывать корректность программы(несколько преувеличено, но я думаю что понятно о чем я).
E>Нет, я не понимаю. здесь
Например:
/// \pre: a > 0void f1(int a);
/// \pre: a > 1void f2(int a)
{
if(a > 0) // <-- эта проверка здесь лишняя, предусловие дает гарантию что a > 0.
{
f1(a);
}
}
И также для постусловий. Плюс ослабление/усиление.
E>Так же я не понимаю, о каких пред- и постусловиях можно говорить в C++
О самых обыкновенных...
E> -- в C++ это разве что благая воля программиста (использование assert-ов или условий проверки).
Или я вопроса не понял.
ЮЖ>>В Вашем случе — баг рассматривается как нечто, которое может вполне себе спокойно существовать в работающей программе. E>Боюсь, что это не только в моем случае. Это, насколько я могу судить, повсеместное явление.
Это не радует );
Re[34]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>>Вот почему-то все думают что если я использую nothrow версию, то я не проверяю параметры...
E>>Вы может и проверяете. Я не всегда проверяю. ЮЖ>Я не говорю о том чтобы проверять всегда.
Если вы не проверяете аргументы max_element всегда и не проверяете результат max_element всегда, тогда у вас нет никаких гарантий того, что однажды вы не разыменуете некорректный итератор.
ЮЖ>>>Разыменование невалидного итератора — эта ситуация которой не может быть вообще. Исходя из пост и предусловий можно доказывать корректность программы(несколько преувеличено, но я думаю что понятно о чем я).
E>>Нет, я не понимаю. ЮЖ>здесь
ЮЖ>Например: ЮЖ>
ЮЖ>/// \pre: a > 0
ЮЖ>void f1(int a);
ЮЖ>/// \pre: a > 1
ЮЖ>void f2(int a)
ЮЖ>{
ЮЖ> if(a > 0) // <-- эта проверка здесь лишняя, предусловие дает гарантию что a > 0.
ЮЖ> {
ЮЖ> f1(a);
ЮЖ> }
ЮЖ>}
ЮЖ>
ЮЖ>И также для постусловий. Плюс ослабление/усиление.
В C++ ничего этого нет. Нет никакой поддержки инваринтов/пред-/постусловий со стороны Run-Time. Разработчики могут только учитывать неформальные спецификации из документации, но не имеют никаких инструментов для проверки своих ожиданий во время исполнения.
Тогда как языки Eiffel и D проверяют инварианты/пред-/постусловия и порождают исключения, если они нарушены. А это означает, что если программа скомпилирована с сохранением предусловий, то функция f2 не будет вызвана с неправильными аргументами вне зависимости от того, знал ли программист о нарушении контракта или не знал.
E>>Так же я не понимаю, о каких пред- и постусловиях можно говорить в C++ ЮЖ>О самых обыкновенных...
Нет в C++ даже самых обыкновенных.
ЮЖ>>>В Вашем случе — баг рассматривается как нечто, которое может вполне себе спокойно существовать в работающей программе. E>>Боюсь, что это не только в моем случае. Это, насколько я могу судить, повсеместное явление. ЮЖ>Это не радует );
Се ля ви.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[35]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>>>Вот почему-то все думают что если я использую nothrow версию, то я не проверяю параметры...
E>>>Вы может и проверяете. Я не всегда проверяю. ЮЖ>>Я не говорю о том чтобы проверять всегда.
E>Если вы не проверяете аргументы max_element всегда и не проверяете результат max_element всегда, тогда у вас нет никаких гарантий того, что однажды вы не разыменуете некорректный итератор.
Достаточно _одной_ проверки.
ЮЖ>>>>Разыменование невалидного итератора — эта ситуация которой не может быть вообще. Исходя из пост и предусловий можно доказывать корректность программы(несколько преувеличено, но я думаю что понятно о чем я).
E>>>Нет, я не понимаю. ЮЖ>>здесь ЮЖ>>И также для постусловий. Плюс ослабление/усиление.
E>В C++ ничего этого нет. Нет никакой поддержки инваринтов/пред-/постусловий со стороны Run-Time.
Из отсутствия поддержки инвариантов не следует что в С++ их нет.
E>Разработчики могут только учитывать неформальные спецификации из документации, но не имеют никаких инструментов для проверки своих ожиданий во время исполнения.
Конструктор user_name проверяет аргумент(std::string) на допустимость и кидает исключения при необходимости. Изменить объект user_name можно только с помощью оператора =. Существование объекта user_name гарантирует выполнение условий, проверяемых _один_раз_ при создании. Не валидных объектов(с точки зрения name_policy) не существует. И т.п., накрутить можно все что угодно, причем полностью прозрачно.
E>Тогда как языки Eiffel и D проверяют инварианты/пред-/постусловия и порождают исключения, если они нарушены.
Про постусловия я не говорил.
А так, если сильно захотеть:
#define assert(exp) MY_ASSERT(exp) // а там throw
Хотя это плохой вариант.
E>А это означает, что если программа скомпилирована с сохранением предусловий, то функция f2 не будет вызвана с неправильными аргументами вне зависимости от того, знал ли программист о нарушении контракта или не знал.
А программисту сложно почитать документацию и выяснить контракт? Или он будет наугад аргументы подставлять, авось заведется?
E>>>Так же я не понимаю, о каких пред- и постусловиях можно говорить в C++ ЮЖ>>О самых обыкновенных...
E>Нет в C++ даже самых обыкновенных.
Можно услышать определение "самых обыкновенных" ?
Re[36]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, Юрий Жмеренецкий, Вы писали:
E>>Если вы не проверяете аргументы max_element всегда и не проверяете результат max_element всегда, тогда у вас нет никаких гарантий того, что однажды вы не разыменуете некорректный итератор. ЮЖ>Достаточно _одной_ проверки.
Это какой?
Я смею утверждать, что _обычный_ программист не будет писать перед вызовом существующего max_element пустоту последовательности. И не будет проверять возвращаемое значение. Он уверен, что:
a) либо последовательность не пуста;
b) либо любое возвращаемое max_element значение удовлетворяет текущему контексту (см. пример skeptika_ с использованием max_element в функции сортировки).
Его вера, иногда, может быть ошибочна. В этих случаях есть шанс получить битую память и наведенную ошибку.
Какая _одна_ проверка способна избавить разработчика от подобной ситуции?
ЮЖ>>>здесь ЮЖ>>>И также для постусловий. Плюс ослабление/усиление.
E>>В C++ ничего этого нет. Нет никакой поддержки инваринтов/пред-/постусловий со стороны Run-Time.
ЮЖ>Из отсутствия поддержки инвариантов не следует что в С++ их нет.
Точно так же можно заявить, что из отсутствия поддержки ООП в C не следует, что в C нет ООП.
E>>Разработчики могут только учитывать неформальные спецификации из документации, но не имеют никаких инструментов для проверки своих ожиданий во время исполнения.
ЮЖ>) Зато в Compile-Time имеют:
ЮЖ>
ЮЖ>Конструктор user_name проверяет аргумент(std::string) на допустимость и кидает исключения при необходимости. Изменить объект user_name можно только с помощью оператора =. Существование объекта user_name гарантирует выполнение условий, проверяемых _один_раз_ при создании. Не валидных объектов(с точки зрения name_policy) не существует. И т.п., накрутить можно все что угодно, причем полностью прозрачно.
С этим согласен. Но это не имеет никакого отношения к обсуждавшемуся дизайну std::max_element.
E>>А это означает, что если программа скомпилирована с сохранением предусловий, то функция f2 не будет вызвана с неправильными аргументами вне зависимости от того, знал ли программист о нарушении контракта или не знал.
ЮЖ>А программисту сложно почитать документацию и выяснить контракт? Или он будет наугад аргументы подставлять, авось заведется?
1. Программисты ошибаются. Даже если читают документацию. А читают они ее не так уж часто, иначе не появилось бы выражение RTFM.
2. Условия меняются. Либо контракты обновляют поставщики библиотек в новых версиях. Либо новые версии ПО начинают несоблюдать контракты. Вспомните Ариан 5 -- очень хороший пример эволюции ПО, когда корректностью контрактов в новом окружении для старого ПО никто не озадачился.
E>>>>Так же я не понимаю, о каких пред- и постусловиях можно говорить в C++ ЮЖ>>>О самых обыкновенных...
E>>Нет в C++ даже самых обыкновенных. ЮЖ>Можно услышать определение "самых обыкновенных" ?
Вот, например. Более полно о контрактах лучше читать толмуд Бертрана Мейера.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[37]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Юрий Жмеренецкий, Вы писали:
E>>>Если вы не проверяете аргументы max_element всегда и не проверяете результат max_element всегда, тогда у вас нет никаких гарантий того, что однажды вы не разыменуете некорректный итератор. ЮЖ>>Достаточно _одной_ проверки.
E>Это какой?
Например вот такой:
template< typename RandomAccessIterator >
void selection_sort( RandomAccessIterator first, RandomAccessIterator last )
{
while( first < --last ) // <-- max_element никогда не будет вызван с пустым интервалом
std::iter_swap( last, std::max_element( first, last + 1 ) );
}
Re[38]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, skeptik_, Вы писали:
E>>>>Если вы не проверяете аргументы max_element всегда и не проверяете результат max_element всегда, тогда у вас нет никаких гарантий того, что однажды вы не разыменуете некорректный итератор. ЮЖ>>>Достаточно _одной_ проверки.
E>>Это какой?
_>Например вот такой:
_>
_>template< typename RandomAccessIterator >
_>void selection_sort( RandomAccessIterator first, RandomAccessIterator last )
_>{
_> while( first < --last ) // <-- max_element никогда не будет вызван с пустым интервалом
_> std::iter_swap( last, std::max_element( first, last + 1 ) );
_>}
_>
Ага. Во всех C++ программах функция std::max_element вызывается всего в одном месте -- в selection_sort. И именно это использование max_element абсолютно безопасно.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[39]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, skeptik_, Вы писали:
E>>>>>Если вы не проверяете аргументы max_element всегда и не проверяете результат max_element всегда, тогда у вас нет никаких гарантий того, что однажды вы не разыменуете некорректный итератор. ЮЖ>>>>Достаточно _одной_ проверки.
E>>>Это какой?
_>>Например вот такой:
_>>
_>>template< typename RandomAccessIterator >
_>>void selection_sort( RandomAccessIterator first, RandomAccessIterator last )
_>>{
_>> while( first < --last ) // <-- max_element никогда не будет вызван с пустым интервалом
_>> std::iter_swap( last, std::max_element( first, last + 1 ) );
_>>}
_>>
E>Ага. Во всех C++ программах функция std::max_element вызывается всего в одном месте -- в selection_sort. И именно это использование max_element абсолютно безопасно.
Что за бред? Я вроде русским языком написал: например. В других местах она тоже не в вакууме вызывается. Я тут провел поиск по диску, нашёл вот max_element например в двух местах в Crypto 5.1, так там условие непустоты интервала является предусловием уже для вызывающей функции.
Re[40]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, skeptik_, Вы писали:
E>>Ага. Во всех C++ программах функция std::max_element вызывается всего в одном месте -- в selection_sort. И именно это использование max_element абсолютно безопасно.
_>Что за бред? Я вроде русским языком написал: например. В других местах она тоже не в вакууме вызывается. Я тут провел поиск по диску, нашёл вот max_element например в двух местах в Crypto 5.1, так там условие непустоты интервала является предусловием уже для вызывающей функции.
Я тоже русским языком написал:
2. Условия меняются. Либо контракты обновляют поставщики библиотек в новых версиях. Либо новые версии ПО начинают несоблюдать контракты.
То, что сейчас применение max_element в Crypto безопасно может оказаться не так в какой-то следующей версии.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[37]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Юрий Жмеренецкий, Вы писали:
E>>>Если вы не проверяете аргументы max_element всегда и не проверяете результат max_element всегда, тогда у вас нет никаких гарантий того, что однажды вы не разыменуете некорректный итератор. ЮЖ>>Достаточно _одной_ проверки.
E>Это какой? E>Я смею утверждать, что _обычный_ программист не будет писать перед вызовом существующего max_element пустоту последовательности. И не будет проверять возвращаемое значение. Он [b]уверен[b], что: E>a) либо последовательность не пуста; E>b) либо любое возвращаемое max_element значение удовлетворяет текущему контексту (см. пример skeptika_ с использованием max_element в функции сортировки).
Уверенность не может быть сама по себе. Она "выводится" из предусловий — где-то компилятором(checked_value), где-то документацией + assert + unit test для него в debug'e.
E>Его вера, иногда, может быть ошибочна. В этих случаях есть шанс получить битую память и наведенную ошибку. E>Какая _одна_ проверка способна избавить разработчика от подобной ситуции?
Одна — в смысле единственная, может быть и две, но выполнены они будут один раз.
Может быть непосредственно перед вызовом max_element, может быть выше по стеку.
ЮЖ>>>>здесь ЮЖ>>>>И также для постусловий. Плюс ослабление/усиление.
E>>>В C++ ничего этого нет. Нет никакой поддержки инваринтов/пред-/постусловий со стороны Run-Time. ЮЖ>>Из отсутствия поддержки инвариантов не следует что в С++ их нет. E>Точно так же можно заявить, что из отсутствия поддержки ООП в C не следует, что в C нет ООП.
Вобщем, опять этот плохой С++? Да, нет поддержки со стороны run-time(assert даже не предлагаю =) ). А какая она должна быть ? Во-первых сами пред/пост условия писать где-то надо, типы исключений указывать надо. Для вложенных вызовов функций, для которых не доступен код, придется воскрешать throw-spec.
Имхо, проще это статически в типах выразить(по возможности).
E>>>Разработчики могут только учитывать неформальные спецификации из документации, но не имеют никаких инструментов для проверки своих ожиданий во время исполнения.
... E>С этим согласен. Но это не имеет никакого отношения к обсуждавшемуся дизайну std::max_element.
Это имеет отношение к фразе про проверку ожиданий.
E>>>А это означает, что если программа скомпилирована с сохранением предусловий, то функция f2 не будет вызвана с неправильными аргументами вне зависимости от того, знал ли программист о нарушении контракта или не знал.
ЮЖ>>А программисту сложно почитать документацию и выяснить контракт? Или он будет наугад аргументы подставлять, авось заведется? E>1. Программисты ошибаются. Даже если читают документацию. А читают они ее не так уж часто, иначе не появилось бы выражение RTFM.
Значит они от своих ошибок маленький feedback получают. Ну возникло исключение InvalidParam, и все хорошо. Развращает такой подход... Вот если бы перевелось не туда миллионов 10$, или спутник бы упал, тогда по три раза читать будут.
E>2. Условия меняются.
Да они всегда меняются...
E>Либо контракты обновляют поставщики библиотек в новых версиях.
Это если им не интересна backward compatibility, или происходит "устаканивание" интерфейсов, т.е. библиотека еще сырая.
E>Либо новые версии ПО начинают несоблюдать контракты. Вспомните Ариан 5 -- очень хороший пример эволюции ПО, когда корректностью контрактов в новом окружении для старого ПО никто не озадачился.
Вот это "хороший" feedback для всей отрасли...
E>>>Нет в C++ даже самых обыкновенных. ЮЖ>>Можно услышать определение "самых обыкновенных" ?
E>Вот, например. Более полно о контрактах лучше читать толмуд Бертрана Мейера.
По ссылке:
Хотя Бертран Мейер советует писать так, чтобы программа работала вообще без каких-либо проверок в финальной версии.
E>Еще раз: программисты ошибаются. ОШИБАЮТСЯ!
Пока что вся эта дискуссия показывает недостатки плюсов как языка по сравнению с полноценным ФП.
Если я правильно понимаю, на ФЯ написать некорректную реализацию max_element практически нереально.
Потому, что непустые последовательности там радикально отличаются от пустых. В итоге программист вынужден явно обработать все случаи:0, 1, и больше элементов.
А все эти припрыгивания с лишним сравнением (которое предположительно снизит производительность для вырожденных случаев) и надеждой на корректную обработку неочевидных контрактов — соревнования в эквилибристике.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, Sinclair, Вы писали:
E>>Еще раз: программисты ошибаются. ОШИБАЮТСЯ! S>Пока что вся эта дискуссия показывает недостатки плюсов как языка по сравнению с полноценным ФП.
Я в этой дискуссии пытаюсь понять вот что: почему C++ники отвергают тот факт, что в C++ возможны ошибки, которые могут приводить к неприятным и неочевидным багам (порча памяти и, как следствие, наведенная ошибка в другом месте)? А уже как следствие этого, почему им не нравится решение, которое от таких ошибок защищает.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[27]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, eao197, Вы писали:
E>Я в этой дискуссии пытаюсь понять вот что: почему C++ники отвергают тот факт, что в C++ возможны ошибки, которые могут приводить к неприятным и неочевидным багам (порча памяти и, как следствие, наведенная ошибка в другом месте)? А уже как следствие этого, почему им не нравится решение, которое от таких ошибок защищает.
Потому что эквилибристика — их вторая натура.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[28]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, eao197, Вы писали:
E>>Я в этой дискуссии пытаюсь понять вот что: почему C++ники отвергают тот факт, что в C++ возможны ошибки, которые могут приводить к неприятным и неочевидным багам (порча памяти и, как следствие, наведенная ошибка в другом месте)? А уже как следствие этого, почему им не нравится решение, которое от таких ошибок защищает. S>Потому что эквилибристика — их вторая натура.
Не их -- наша!
C++ forever!!!
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[27]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, eao197, Вы писали:
E>Я в этой дискуссии пытаюсь понять вот что: почему C++ники отвергают тот факт, что в C++ возможны ошибки, которые могут приводить к неприятным и неочевидным багам (порча памяти и, как следствие, наведенная ошибка в другом месте)? А уже как следствие этого, почему им не нравится решение, которое от таких ошибок защищает.
Это тебе только кажется. Твой подход имеет право на жизнь и даже в стандартной библиотеке , но выло выбрано другое решенеи. Какие использовались критерии я уже говорил. Плохо ли выбранное решение ? думаю что нет.
Не хочу показаться нудным но для полного низкоуровнего контроля существуют другие языки и другие подходы, может именно поэтому стандартная библиотке следует получившимуся дизайну.
Т.е. Это "странное" отношение к дизайну , некое религиозное. У рассмотренных (и у ваших) решений есть свои преимущества и недостатки.
P.S. Меня кстати в стандартной библиотеке немного удивляет отсутствие класса Range который инкапсулирует пару итераторов. С таким классом валидация диапазонов может происходить на этапе конструирования.
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[28]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, minorlogic, Вы писали:
M>Здравствуйте, Alxndr, Вы писали:
M>>>[] для полного низкоуровнего контроля существуют другие языки []
A>>Какие?
M>Жаба ? С шарп ?
Вероятно, имелся в виду "контроль исполнения"?
Re[38]: Почему преждевременная оптимизация - корень всех зол
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Уверенность не может быть сама по себе. Она "выводится" из предусловий — где-то компилятором(checked_value), где-то документацией + assert + unit test для него в debug'e.
Ничего из этого не может гарантировать отсутствие ошибок в программе.
ЮЖ>Одна — в смысле единственная, может быть и две, но выполнены они будут один раз. ЮЖ>Может быть непосредственно перед вызовом max_element, может быть выше по стеку.
Если выше по стеку, то сложно этой проверке доверять после проведения рефакторингов.
E>>>>В C++ ничего этого нет. Нет никакой поддержки инваринтов/пред-/постусловий со стороны Run-Time. ЮЖ>>>Из отсутствия поддержки инвариантов не следует что в С++ их нет. E>>Точно так же можно заявить, что из отсутствия поддержки ООП в C не следует, что в C нет ООП.
ЮЖ>Вобщем, опять этот плохой С++? Да, нет поддержки со стороны run-time(assert даже не предлагаю =) ). А какая она должна быть ?
Посмотрите на Eiffel. Ну или на D, хотя там в постусловиях нет old, если не ошибаюсь.
ЮЖ>типы исключений указывать надо.
Не, типы исключений не надо. А вот nothrow-спецификатор очень бы не помешал.
E>>1. Программисты ошибаются. Даже если читают документацию. А читают они ее не так уж часто, иначе не появилось бы выражение RTFM. ЮЖ>Значит они от своих ошибок маленький feedback получают. Ну возникло исключение InvalidParam, и все хорошо. Развращает такой подход... Вот если бы перевелось не туда миллионов 10$, или спутник бы упал, тогда по три раза читать будут.
Ариан 5 взорвался на старте. А спустя несколько лет Mars Climate Orbiter потерпел крушение по аналогичным причинам (неправильное переиспользование кода). Так что не похоже, что даже крах спутников учит программистов читать документацию.
E>>Либо контракты обновляют поставщики библиотек в новых версиях. ЮЖ>Это если им не интересна backward compatibility
Бывает и так.
E>>Либо новые версии ПО начинают несоблюдать контракты. Вспомните Ариан 5 -- очень хороший пример эволюции ПО, когда корректностью контрактов в новом окружении для старого ПО никто не озадачился. ЮЖ>Вот это "хороший" feedback для всей отрасли...
См. выше.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[31]: Почему преждевременная оптимизация - корень всех зол