Re[15]: Почему преждевременная оптимизация - корень всех зол
От: nikov США http://www.linkedin.com/in/nikov
Дата: 22.08.08 14:27
Оценка:
Здравствуйте, eao197, Вы писали:

E>Вроде как автор max_element -- он же тут чистенький, весь такой в белом, у него код корректный. А то, что он создает своим корректным кодом лишние заботы пользователю -- так это проблема пользователя


Если он описал в документации поведение метода для массива нулевой длины — то он действительно весь в белом.
Re[15]: Почему преждевременная оптимизация - корень всех зол
От: skeptik_  
Дата: 22.08.08 14:28
Оценка:
Здравствуйте, eao197, Вы писали:

E>Вроде как автор max_element -- он же тут чистенький, весь такой в белом, у него код корректный. А то, что он создает своим корректным кодом лишние заботы пользователю -- так это проблема пользователя


Так как это обычный для STL подход, то пользователю не нужно запоминать, что моя функция ведёт себя отличным от STL образом.
Re[15]: Почему преждевременная оптимизация - корень всех зол
От: CreatorCray  
Дата: 22.08.08 14:36
Оценка: :))
Здравствуйте, eao197, Вы писали:

E>Из исходного условия так же не понятно, требовалась ли максимально безопасная (с проверками параметров) или максимально быстрая версия. Применительно к C++, имхо, логичнее было бы предполагать максимально быструю версию (максимум, что в ней может быть еще -- это набор ассертов).

Мне это все больше напоминает картинку "что хотел заказчик" http://www.4p.ru/images/nsmail79.gif
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[16]: Почему преждевременная оптимизация - корень всех зол
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 22.08.08 14:45
Оценка:
Здравствуйте, nikov, Вы писали:

E>>Вроде как автор max_element -- он же тут чистенький, весь такой в белом, у него код корректный. А то, что он создает своим корректным кодом лишние заботы пользователю -- так это проблема пользователя


N>Если он описал в документации поведение метода для массива нулевой длины — то он действительно весь в белом.


Не думаю. Есть два способа проектировать интерфейсы библиотек:
1. Простота, стройность, ортогональность и единообразие с точки зрения разработчика библиотеки. Подход с итераторами в STL -- это пример такого подхода.
2. Простота использования и освоения с точки зрения пользователя библиотеки.

Эти понятия взаимоисключающие. Пример с max_element в этом плане показателен. Разработчик max_element в STL-стиле сделал реализацию, которая единым образом обрабатывает как наличие элементов в последовательности, так и их отсутствие. Зато пользователь получает головную боль в виде необходимости самостоятельной проверки результата max_element.

По сути, разработчик max_element отказался от выполнения проверок и принятия решения и переложил эту заботу на пользователя. Но пользователи они же (мы же) такие, что не хотим лишних забот. Ах передали в max_element пустую последовательность, ну чтож, бывает, чтож вы нам ничего по этому поводу не сказали, а вернули какой-то end?

В результате тот же if(), который будет проверять наличие максимального элемента, все равно будет написан (только уже другим человеком). Или не написан с той же самой степенью вероятности.

Применительно к C++ у разработчика max_element, по большому счету выбора нет, т.к. он не знает, что делать с пустой последовательностью: кидать исключение, возвращать значение по умолчанию, вызвать abort(), устанавливать errno или делать еще что-нибудь. Т.к. в C++ нет общих подходов к обработке ошибок. А вот в более современных языках, в которых исключения были с самого начала, исключение из max_element при пустой последовательности было бы более приемлимым решением.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[17]: Почему преждевременная оптимизация - корень всех зол
От: skeptik_  
Дата: 22.08.08 15:24
Оценка: +2 -1
Здравствуйте, eao197, Вы писали:

E>По сути, разработчик max_element отказался от выполнения проверок и принятия решения и переложил эту заботу на пользователя. Но пользователи они же (мы же) такие, что не хотим лишних забот. Ах передали в max_element пустую последовательность, ну чтож, бывает, чтож вы нам ничего по этому поводу не сказали, а вернули какой-то end?


E>Применительно к C++ у разработчика max_element, по большому счету выбора нет, т.к. он не знает, что делать с пустой последовательностью: кидать исключение, возвращать значение по умолчанию, вызвать abort(), устанавливать errno или делать еще что-нибудь. Т.к. в C++ нет общих подходов к обработке ошибок. А вот в более современных языках, в которых исключения были с самого начала, исключение из max_element при пустой последовательности было бы более приемлимым решением.


Это мнимое удобство. Отлавливать исключения ничем не более удобно, чем проверить итератор. Твой подход на самом деле ведёт к такому вот коду:
map< A, B > m;
try {
  B b = m.find( a );
  // do something if a found
}
catch( SomeException const& e ) {
  // do something if a not found
}

Это тоже архитектурная ошибка — кидать исключения, когда ситуация не является truly exceptional. И в данном случае это не так, ибо внутри функции max_element у нас недостаточно знаний о том, является ли ситуация исключительной.
Re[18]: Почему преждевременная оптимизация - корень всех зол
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 22.08.08 15:40
Оценка: +2
Здравствуйте, skeptik_, Вы писали:

_>Это мнимое удобство. Отлавливать исключения ничем не более удобно, чем проверить итератор. Твой подход на самом деле ведёт к такому вот коду:

_>
_>map< A, B > m;
_>try {
_>  B b = m.find( a );
_>  // do something if a found
_>}
_>catch( SomeException const& e ) {
_>  // do something if a not found
_>}
_>


Упс, а откуда map и find взялись? Подмена темы не пройдет!

_>Это тоже архитектурная ошибка — кидать исключения, когда ситуация не является truly exceptional.


В случае с map::find отсутствие заданного ключа является нормальной ситуацией. А вот попытку найти максимальный элемент в пустой последовательности нормальной ситуацией назвать тяжело.

Когда пользователь вызывает max_element, то нормально считать, что он позаботился о том, чтобы элементы в последовательности были. Если же их нет, то это явная ошибка. И сообщить о ней нужно сразу в месте обнаружения (то бишь в max_element).

_> И в данном случае это не так, ибо внутри функции max_element у нас недостаточно знаний о том, является ли ситуация исключительной.


Извлечение квадратного корня из отрицательного числа, в принципе, имеет больше смысла, чем max_element от пустой последовательности. Но почему-то большинство реализаций sqrt в разных языках либо выбрасывают исключения domain_error, либо абортируют программу.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[19]: Почему преждевременная оптимизация - корень всех зол
От: skeptik_  
Дата: 22.08.08 15:50
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, skeptik_, Вы писали:


_>>Это тоже архитектурная ошибка — кидать исключения, когда ситуация не является truly exceptional.


E>В случае с map::find отсутствие заданного ключа является нормальной ситуацией. А вот попытку найти максимальный элемент в пустой последовательности нормальной ситуацией назвать тяжело.


E>Когда пользователь вызывает max_element, то нормально считать, что он позаботился о том, чтобы элементы в последовательности были. Если же их нет, то это явная ошибка. И сообщить о ней нужно сразу в месте обнаружения (то бишь в max_element).


То есть, ты считаешь, что практически все алгоритмы в STL надо было писать так:
template< typename Iterator >
... some_algorithm( Iterator first, Iterator last, ... )
{
    if ( first == last )
        throw ...;
    ...
}

Так?
Re[20]: Почему преждевременная оптимизация - корень всех зол
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 22.08.08 16:10
Оценка:
Здравствуйте, skeptik_, Вы писали:

_>То есть, ты считаешь, что практически все алгоритмы в STL надо было писать так:

_>
_>template< typename Iterator >
_>... some_algorithm( Iterator first, Iterator last, ... )
_>{
_>    if ( first == last )
_>        throw ...;
_>    ...
_>}
_>

_>Так?

Во-первых, я считаю, что STL подход с итераторами вида [begin, end) это всего лишь один из возможных. Да, он принят в языке, но это вовсе не означает, что он лучший.

Во-вторых, я считаю, что в языке с контрактами такие вещи записываются гораздо лучше. Что-то вроде:
max_element (where: COLLECTION[T]): T
  requires
    non_empty_collection: 0 /= where.size
  ...

Если для скорости программы проверки не критичны, то исключение о нарушении контракта, порожденное самим run-time гораздо лучше, чем запрограммированные кем-то проверки. Если же скорость критична настолько, что даже проверки недопустимы, то получается тоже самое, что и в C++.

В-третьих, не буду говорить за все алгоритмы STL, то в некоторых случаях я бы хотел иметь выбор между функциями:
template< class ITERATOR >
typename ITERATOR::value_type
max_element( ITERATOR begin, ITERATOR end ) { ... }

template< class ITERATOR >
ITERATOR
max_element_ref( ITERATOR begin, ITERATOR end ) { ... }

где max_element может бросать исключения.

И, в-четвертых, мне кажется, что написание таких с виду простых и фундаментальных вещей как max_element или buble_sort вовсе не так тривиально и однозначно, как это кажется на первый взгляд.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[15]: Почему преждевременная оптимизация - корень всех зол
От: minorlogic Украина  
Дата: 22.08.08 16:47
Оценка:
Здравствуйте, eao197, Вы писали:

E>Вроде как автор max_element -- он же тут чистенький, весь такой в белом, у него код корректный. А то, что он создает своим корректным кодом лишние заботы пользователю -- так это проблема пользователя


А вы знаете альтернативу ? поделитесь.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[16]: Почему преждевременная оптимизация - корень всех зол
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 23.08.08 05:25
Оценка: +3
Здравствуйте, minorlogic, Вы писали:

E>>Вроде как автор max_element -- он же тут чистенький, весь такой в белом, у него код корректный. А то, что он создает своим корректным кодом лишние заботы пользователю -- так это проблема пользователя


M>А вы знаете альтернативу ? поделитесь.


Если речь о C++, то я бы предпочел иметь набор из функций:
// Бросает исключение в случае пустой последовательности.
T max_element( FI begin, FI end );
// Не бросает исключений, но вызывает abort.
T max_element( FI begin, FI end, nothrow );
// Возвращает ссылку на максимальный элемент или end.
// Не бросает исключений.
FI max_element_reference( FI begin, FI end );


Только, боюсь, в современном C++ это невозможно.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[17]: Почему преждевременная оптимизация - корень всех зол
От: minorlogic Украина  
Дата: 23.08.08 08:08
Оценка: -1
Здравствуйте, eao197, Вы писали:

E>Только, боюсь, в современном C++ это невозможно.


Таким образом ты подтверждаешь что std::max_element это лучшее решение, поскольку лучше ты не можешь предложить в рамках языка ?

P.S. в таком куске незначительной функциональности , я бы не хотел чтобы язык за меня делал выбор стратегии обработки ошибок. Поэтому возвращать указатель на последний (невалидный) элемент это мегаудачное решение.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[18]: Почему преждевременная оптимизация - корень всех зол
От: VoidEx  
Дата: 23.08.08 12:32
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>P.S. в таком куске незначительной функциональности , я бы не хотел чтобы язык за меня делал выбор стратегии обработки ошибок. Поэтому возвращать указатель на последний (невалидный) элемент это мегаудачное решение.


Т.е. сообщение об ошибке возвратом указателя на невалидный элемент — это мегаудочное решение, но при этом это не "выбор стратегии обработки ошибки"? Это как так?
Re[19]: Почему преждевременная оптимизация - корень всех зол
От: minorlogic Украина  
Дата: 23.08.08 12:52
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Здравствуйте, minorlogic, Вы писали:


M>>P.S. в таком куске незначительной функциональности , я бы не хотел чтобы язык за меня делал выбор стратегии обработки ошибок. Поэтому возвращать указатель на последний (невалидный) элемент это мегаудачное решение.


VE>Т.е. сообщение об ошибке возвратом указателя на невалидный элемент — это мегаудочное решение, но при этом это не "выбор стратегии обработки ошибки"? Это как так?


Просто , это не ребует усилий от програмитста. Можешь проверить , а можешь нет . Не вводится новый механизм , флаг или код возврата или исключения. На мой взгляд , очень удачное решение.

Обсуждать решение я готов только в сравнении с альтернативным.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[20]: Почему преждевременная оптимизация - корень всех зол
От: VoidEx  
Дата: 23.08.08 13:49
Оценка: +1
Здравствуйте, minorlogic, Вы писали:

M>Просто , это не ребует усилий от програмитста. Можешь проверить , а можешь нет . Не вводится новый механизм , флаг или код возврата или исключения. На мой взгляд , очень удачное решение.


M>Обсуждать решение я готов только в сравнении с альтернативным.


Как раз eao197 и предлагает набор функций, чтобы способ обработки ошибки выбирал программист, а не библиотека. В данном же случае, способ выбран за программиста.
Re: Потому что - преждевременная!
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 23.08.08 14:01
Оценка: 13 (1) +8
Здравствуйте, Аноним, Вы писали:

А>Ведь оптимизация может привести к переписыванию много чего и даже в рамках одного модуля или класса. Какой смысл в этой фразе?


Это тонкая подколка патриархов IT. В фразе "premature optimization is a root of evil" ключевое слово не "optimization", а "premature". Многие попросту не понимают, что этим афоризмом отмечается не какой-то априорно негативный хараткер оптимизации, выполняемой до профилирования (там уже и в самом деле может оказаться поздно что-то оптимизировать), а лишь то, что вредно оптимизировать код, руководствуясь неполными предположениями о характере работы программы. Только и всего.

Сиречь, корень зол в постановке лошади позади телеги. Только и всего.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[18]: Почему преждевременная оптимизация - корень всех зол
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 23.08.08 15:27
Оценка:
Здравствуйте, minorlogic, Вы писали:

E>>Только, боюсь, в современном C++ это невозможно.


M>Таким образом ты подтверждаешь что std::max_element это лучшее решение, поскольку лучше ты не можешь предложить в рамках языка ?


Возможно, мои опасения напрасны и даже в рамках C++98/2003 можно реализовать предложенный мной набор функций. Выделив отдельные варианты для указателей и итераторов:
// Бросают исключение.
template< class T >
T & max_element( T * begin, T * end ) { ... }
template< class T >
const T & max_element( const T * begin, const T * end ) { ... }
template< class FI >
typename FI::reference_type max_element( FI begin, FI end ) { ... }
... аналогично остальные функции ...


Так что не подтверждаю.

M>P.S. в таком куске незначительной функциональности , я бы не хотел чтобы язык за меня делал выбор стратегии обработки ошибок. Поэтому возвращать указатель на последний (невалидный) элемент это мегаудачное решение.


Мне сложно назвать мегаудачным решение, при котором миллионы пользователей вынуждены проверять условие, которое мог проверить и обработать один разработчик max_element. Поскольку мне кажется очень странным использование max_element в стиле:
std::vector< int > v;
... какие-то действия, которые, по мнению разработчика, заполняют v...
std::vector< int >::iterator m = std::max_element( v.begin(), v.end() );
if( m == v.end() )
  // Что за оно вааще?!!

Ведь обращение к max_element делается в уверенности, что последовательность не пуста (аналогичная уверенность у разработчика есть при вызове sqrt -- он просто на 100% убежден, что его аргумент не отрицателен). Имея такую уверенность обычный разработчик вряд ли будет писать проверку возвращенного итератора. Как следствие -- неопределенное поведение программы.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[17]: Почему преждевременная оптимизация - корень всех зол
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.08.08 03:43
Оценка:
Здравствуйте, eao197, Вы писали:


E>Только, боюсь, в современном C++ это невозможно.

Почему невозможно? Ты имеешь в виду существующий STL? В языке никаких проблем сделать nothrow я не вижу.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Почему преждевременная оптимизация - корень всех зол
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 25.08.08 06:56
Оценка:
Здравствуйте, Sinclair, Вы писали:

E>>Только, боюсь, в современном C++ это невозможно.

S>Почему невозможно? Ты имеешь в виду существующий STL?

Я боялся, что подобная реализация выльется в большое количество перегруженных функций (чтобы разделить случаи итераторов и указателей):
// Бросают исключение.
template< class T >
T & max_element( T * begin, T * end ) { ... }
template< class T >
const T & max_element( const T * begin, const T * end ) { ... }
template< class FI >
typename FI::reference_type max_element( FI begin, FI end ) { ... }
... аналогично остальные функции ...

и что все равно окажутся какие-то случаи, которые не будут поддержаны. Но, вероятно, мои опасения напрасны.

S>В языке никаких проблем сделать nothrow я не вижу.


А он уже есть nothrow, но используется пока только для new.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[19]: Почему преждевременная оптимизация - корень всех зол
От: skeptik_  
Дата: 25.08.08 11:00
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Sinclair, Вы писали:


E>>>Только, боюсь, в современном C++ это невозможно.

S>>Почему невозможно? Ты имеешь в виду существующий STL?

E>Я боялся, что подобная реализация выльется в большое количество перегруженных функций (чтобы разделить случаи итераторов и указателей):

А зачем их делить? Шаблонная функция работает одинаково хорошо и с указателями, и с итераторами.
Re[20]: Почему преждевременная оптимизация - корень всех зол
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 25.08.08 11:05
Оценка:
Здравствуйте, skeptik_, Вы писали:

E>>Я боялся, что подобная реализация выльется в большое количество перегруженных функций (чтобы разделить случаи итераторов и указателей):

_>А зачем их делить? Шаблонная функция работает одинаково хорошо и с указателями, и с итераторами.

Вопрос в определении типа возвращаемого функцие значения. Для указателя тип возвращаемого значения выводится элементарно. Для итератора -- через вложенный тип reference_type.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.