[boost][mpl][variant] гетерогенная очередь
От: jazzer Россия Skype: enerjazzer
Дата: 02.04.08 09:44
Оценка: 155 (19)
Чтобы более не захламлять дискуссию (http://www.rsdn.ru/Forum/message/2887515.aspx
Автор: eao197
Дата: 24.03.08
), отвечаю отдельным сообщением, как обещал.

Итак,

Задача

Есть старый API к одной очень распространенной в банковской сфере системе посылки сообщений (все имена, естественно, изменены).
Ключевая особенность работы с ним состоит в том, что для каждого сообщения имеется свой класс (Msg1, Msg2, ...), и для обработки сообщений нужно просто отдать в API функцию с одним аргументом сооответствующего типа, и API ее позовет, когда это сообщение придет.
Сейчас приложение уже есть и работает, через все эти функции обратного вызова. Все сообщения обрабатываются в реальном времени.
Задача: добавить обработку старых сообщений, которые проигрываются сервером при старте приложения.

Проблемы

Прелестей у этого API много, вот две, которые нас особенно заинтересуют сейчас:
1. При (пере)запуске программы, во время проигрывания старых сообщений, сервер посылает их не в том порядке, в котором они приходили в реальной жизни. Но обрабатывать, естественно, надо в правильном порядке, а это значит, что сначала нужно все старые сообщения получить, куда-то сложить, отсортировать, и только после этого уже начать обрабатывать.
2. Классы для разных типов сообщений не имеют общего предка, а это означает, что сложить их в нормальный контейнер по указателю на базовый класс не удастся.

Анализ

Стало быть, стоит задача каким-то образом из все-таки в один контейнер сложить и как-то отсортировать, после чего начать обрабатывать, причем опять же каждое — в соответствии с его типом.
Начнем прояснять с конца:

как сортировать?

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

А если время одинаковое?

Возникает следующий вопрос — а что делать, если у нас есть два сообщения, и у них время одинаковое? Это вполне вероятно, потому что разрешение системы невелико — десятки миллисекунд.
В произвольном порядке их обрабатывать нельзя, потому что между ними есть зависимость, и в реальной жизни сообщения одного типа приходят всегда раньше сообщений другого типа (т.е. сначала приходит сообщение типа Msg1 с чем-нть вроде "произошла ошибка" и в другом поле текст ошибки, а потом приходит сообщение типа Msg2, в котором записано, что текущий статус связанного с ним объекта — неудача, и ты знаешь, что причина неудачи — как раз в пришедшем ранее Msg1).
Ниже я вернусь к тому, как выразить этот упорядоченность типов сообщений в коде.

Далее, что если у нас оказались с одним и тем же временем сообщения одного типа? Тут тоже можно кое-что придумать: например, сообщения типа Msg1 имеют поле со счетчиком, а Msg2 — с номером объекта, на который они ссылаются (т.е. тоже своего рода счетчик в виде внешнего ключа), и т.д.
В коде это тоже выражается очень просто — пишется какая-нть перегруженная функция compare_type с двумя аргументами одного типа, для каждого типа сообщения, и внутри производится упорядочение. Опять же, этот код тоже придется писать при любом решении.

Итак, на текущий момент мы имеем:

1. перегруженную функцию get_time_field, с помощью которой мы можем упорядочить сообщения по времени, независимо от типа сообщения (в этом примере она просто вернет сишную строку, которые можно будет сравнить банальной strcmp);
2. перегруженную функцию compare_type, с помощью которой мы можем упорядочить сообщения одного типа с одной и той же временной меткой.

Это то, что нам будет нужно при любой организации контейнера.

Нам осталось решить две задачи:

1. Упорядочить сообщения разных типов с одной и той же временной меткой.
2. Сложить сообщения разных типов в какой-нибудь контейнер.
3. Призовая задача — у нас уже есть оттестированные функции-обработчики для каждого типа сообщений (см. начало истории), хорошо бы их и заюзать для обработки сохраненных сообщений, по возможности без изменения.

Решение

Я применил следующее решение.

1. В контейнере у нас будет лежать вариант, который может принимать объекты только этих трех типов. Особенно хорошо для этой цели подходит boost::variant, так как в нем есть очень полезная штука — static visitor. В двух словах это означает, что ты передаешь варианту перегруженную по хранимому типу функцию (или вообще одну шаблонную), и вариант сам вызовет правильную версию в зависимости от того, что в нем находится. За подробностями — сюда: http://www.boost.org/doc/libs/1_35_0/doc/html/variant.html.

2. В качестве контейнера выберем обычный std::multiset, предоставив ему соответствующий компаратор, в котором мы инкапсулируем все наши сравнения.
В компаратор, конечно, придут не объекты самих классов сообщений, а варианты, но мы предоставим самому варианту с этим разбираться, позвав функцию boost::apply_visitor — она сама вызовет то, что нам нужно (а именно, сам же компаратор, но уже с правильными аргументами). Эта же boost::apply_visitor позволит нам решить вопрос перебора сообщений в очереди.

Например, мы хотим в целях отладки распечатать очередь после того, как мы получили все старые сообщения, только вот беда — разработчики API, которые добавили в сообщения метод print(), не знали слова const. Пишем простенький функтор с кастом (шаблонный, чтоб сработал для всех типов сообщений):
struct MsgPrinter : boost::static_visitor<> {
  template <class T>
  void operator()(const T& x) const { const_cast<T&>(x).print(); }
};

И прогоняем его нашей очереди:
MsgPrinter print;
std::for_each( msg_queue.begin(), msg_queue.end(), boost::apply_visitor( print ) );

Аналогично вызываем и уже имеющиеся функции обратного вызова для реальной обработки сообщений из очереди.

Тем самым мы одним махом решили задачи 2 и 3.

3. Для упорядочения объектов разных типов обратимся к библиотеке boost::mpl (http://www.boost.org/doc/libs/1_35_0/libs/mpl/doc/index.html) и сведем задачу к упорядочению самих типов. Сделать это очень просто — надо сложить типы сообщений в mpl::vector (http://www.boost.org/doc/libs/1_35_0/libs/mpl/doc/refmanual/vector.html) в том порядке, который нам нужен, и просто сравнивать позиции типов примерно в таком стиле (MsgTypes — это тот самый вектор):
  typedef boost::mpl::vector< Msg1, Msg2, Msg3 > MsgTypes;

  template <typename T, typename U>
  bool compare_type(const T& left, const U& right) const
  {
    // compare type position in the MsgTypes
    return
      boost::mpl::find< MsgTypes, T >::type::pos::value
      <
      boost::mpl::find< MsgTypes, U >::type::pos::value;
  }

Пояснения:
boost::mpl::find< MsgTypes, T > — это алгоритм, который ищет тип Т в последовательности типов MsgTypes (http://www.boost.org/doc/libs/1_35_0/libs/mpl/doc/refmanual/find.html),
boost::mpl::find< MsgTypes, T >::type — это вызов алгоритма, получаем итератор, который возвращает этот алгоритм,
boost::mpl::find< MsgTypes, T >::type::pos — это позиция итератора по отношению к началу последовательности (это все еще тип, в котором лежит число),
boost::mpl::find< MsgTypes, T >::type::pos::value — это сам номер, который можно сравнить с любым другим числом, известным во время компиляции, что мы и делаем.

Кстати, вариант можно собрать из mpl::vector, чем мы немедленно и воспользуемся.


Окончательное решение

Ниже привожу окончательное решение (все поместилось на одной странице простейшего кода):
#include <set>

#include "boost/variant.hpp"
#include "boost/mpl/vector.hpp"
#include "boost/mpl/find.hpp"

#include "MsgAPI.hpp" // defines Msg1, Msg2, Msg3

typedef boost::mpl::vector< Msg1, Msg2, Msg3 > MsgTypes;

class MsgComparer : public boost::static_visitor<bool>
{
  const char* get_time_field( const Msg1& x ) const { return x.sending_time; }
  const char* get_time_field( const Msg2& x ) const { return x.update_time; }
  const char* get_time_field( const Msg3& x ) const { return x.orig_time; }

  template <typename T, typename U>
  bool compare_type(const T& left, const U& right) const
  {
    // compare type position in the MsgTypes
    return
      boost::mpl::find< MsgTypes, T >::type::pos::value
      <
      boost::mpl::find< MsgTypes, U >::type::pos::value;
  }

  // comparators for same type
  bool compare_type(const Msg1& left, const Msg1& right) const
  {
    return strcmp( left.seq_num, right.seq_num ) == -1;
  }

  bool compare_type(const Msg2& left, const Msg2& right) const
  {
    return strcmp( left.external_id, right.external_id ) == -1;
  }

  bool compare_type(const Msg3& left, const Msg3& right) const
  {
    return left.counter < right.counter;
  }

public:
  template <typename T, typename U>
  bool operator()( const T& left, const U& right ) const
  {
    const int r = strcmp( get_time_field( left ), get_time_field( right ) );
    switch (r)
    {
      case -1: return true;
      case  1: return false;
      default: return compare_type( left, right );
    }
  }
};

// The variant Msg (let's call it MegaMsg) :)
typedef boost::make_variant_over< MsgTypes >::type MegaMsg;

// The queue
typedef std::multiset< MegaMsg, MsgComparer > Msgs;

// Specialization for MegaMsg - jump from variant to specific message types
template <>
inline
bool MsgComparer::operator()( const MegaMsg& left, const MegaMsg& right ) const
{
  return boost::apply_visitor(*this, left, right);
}
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: [boost][mpl][variant] гетерогенная очередь
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.04.08 12:45
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Сейчас приложение уже есть и работает, через все эти функции обратного вызова. Все сообщения обрабатываются в реальном времени.


Уточняющий вопрос: судя по тому, что используется std::multiset, имеющееся в задаче реальное время не налагает серьезных ограничений на использование динамической памяти. Соответственно, альтернативные варианты, в которых будут использоваться, скажем, списки умных указателей на некие объекты-интерфейсы, как непригодные по требованиям реального времени отвергаться не будут?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: [boost][mpl][variant] гетерогенная очередь
От: Аноним  
Дата: 02.04.08 14:29
Оценка:
Здравствуйте, jazzer, Вы писали:

Может для нериалтайма и есть время упорядочить, сложить в контейнер но в реальной жизни под высокими нагрузками надо делать все на лету.
Re: [boost][mpl][variant] гетерогенная очередь
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.04.08 14:57
Оценка:
Здравствуйте, jazzer

Вот первый вариант, который пришел в голову: полный файл.

Поскольку я не понял, как создаются объекты Msg1, Msg2, Msg3, то позволил себе сохранять их копию в обертке MessageHandler. А для самих MessageHandler использовать умный указатель (т.к. я пользуюсь ACE, то вместо boost::shared_ptr использовал ACE_Refcounted_Auto_Ptr).

По сравнению с твоим решением я пока вижу у своего два серьезных недостатка:
1. Идентификаторы тегов для типов нужно проставлять вручную. У тебя же они выводятся неявно исходя из позиции в векторе типов. С другой стороны, у тебя все типы собраны в одном месте + есть какие-то органичения на их количество связанные с емкостью mpl::vector (и глубиной инстанциирования шаблонов). У меня таких ограничений нет.

2. У меня нет возможности реализовать сравнение двух разных типов сообщений. Так, у тебя можно определить compare_type(Msg1, Msg2), а у меня это нельзя в принципе. И это самый фатальный недостаток.

Собственно прикладная часть занимает не так много места:
template< class T > struct TypeTag {};

template<> struct TypeTag<Msg1> { static const int value = 0; };
template<> struct TypeTag<Msg2> { static const int value = TypeTag<Msg1>::value + 1; };
template<> struct TypeTag<Msg3> { static const int value = TypeTag<Msg2>::value + 1; };

class AbstractMessageHolder {
    public :
        virtual ~AbstractMessageHolder() {}

        virtual void callApi() = 0;
        virtual void print() const = 0;
        virtual int getTime() const = 0;
        virtual int compareWith( const AbstractMessageHolder & other ) const = 0;
        virtual int typeTag() const = 0;
        virtual const void * rawPointer() const = 0;
};

typedef ACE_Refcounted_Auto_Ptr< AbstractMessageHolder, ACE_Null_Mutex >
        AbstractMessageHolderAutoPtr;

template< class T >
class MessageHolder : public AbstractMessageHolder {
    public :
        MessageHolder( const T & value ) : msg( value ) {}

        virtual void callApi() { apiCall( msg ); }
        virtual void print() const { apiCall( const_cast< T& >( msg ) ); }
        virtual int getTime() const { return ::getTime( msg ); }
        virtual int compareWith( const AbstractMessageHolder & other ) const {
            int r = getTime() - other.getTime();
            if( !r ) {
                r = typeTag() - other.typeTag();
                if( !r ) {
                    r = compareType(
                            msg,
                            *(reinterpret_cast< const T*>( other.rawPointer() )) );
                }
            }
            return r;
        }
        virtual int typeTag() const { return TypeTag<T>::value; }
        virtual const void * rawPointer() const { return &msg; }

    private :
        T msg;
};

template< class T >
AbstractMessageHolderAutoPtr makeMessageHolder( const T & o ) {
    return AbstractMessageHolderAutoPtr( new MessageHolder< T >( o ) );
}

struct MessageHolderComparator {
    bool operator()(
        const AbstractMessageHolderAutoPtr & a,
        const AbstractMessageHolderAutoPtr & b ) {
        return a->compareWith( *b ) < 0;
    }
};

typedef std::multiset<
                AbstractMessageHolderAutoPtr,
                MessageHolderComparator >
        MessageContainer;


При запуске выдает:
calling API...
api on Msg3: 1, 8
api on Msg3: 1, 9
api on Msg1: 2, 4
api on Msg2: 2, 0
api on Msg2: 3, 0
api on Msg2: 3, 1
api on Msg2: 3, 4
api on Msg3: 3, 0
api on Msg1: 4, 2
api on Msg1: 4, 3
printing messages...
api on Msg3: 1, 8
api on Msg3: 1, 9
api on Msg1: 2, 4
api on Msg2: 2, 0
api on Msg2: 3, 0
api on Msg2: 3, 1
api on Msg2: 3, 4
api on Msg3: 3, 0
api on Msg1: 4, 2
api on Msg1: 4, 3


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: [boost][mpl][variant] гетерогенная очередь
От: jazzer Россия Skype: enerjazzer
Дата: 02.04.08 15:14
Оценка:
Здравствуйте, eao197, Вы писали:

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


J>>Сейчас приложение уже есть и работает, через все эти функции обратного вызова. Все сообщения обрабатываются в реальном времени.


E>Уточняющий вопрос: судя по тому, что используется std::multiset, имеющееся в задаче реальное время не налагает серьезных ограничений на использование динамической памяти.

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

E>Соответственно, альтернативные варианты, в которых будут использоваться, скажем, списки умных указателей на некие объекты-интерфейсы, как непригодные по требованиям реального времени отвергаться не будут?


Не будут
Если они не будут оказывать влияния на режим реального времени, естественно
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: [boost][mpl][variant] гетерогенная очередь
От: jazzer Россия Skype: enerjazzer
Дата: 02.04.08 15:16
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>Может для нериалтайма и есть время упорядочить, сложить в контейнер но в реальной жизни под высокими нагрузками надо делать все на лету.


На каком лету, если можно обрабатывать только в правильном порядке, а его можно получить только получив и отсортировав все сообщения?

А рилтайм уже начнется потом, когда все старые сообщения обработаны
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: [boost][mpl][variant] гетерогенная очередь
От: Roman Odaisky Украина  
Дата: 02.04.08 15:23
Оценка: +1
Здравствуйте, eao197, Вы писали:

E>Вот первый вариант, который пришел в голову: полный файл.


Ну у него boost::variant, а у тебя аналог boost::any. Отсюда следуют все преимущества и недостатки.
До последнего не верил в пирамиду Лебедева.
Re[3]: [boost][mpl][variant] гетерогенная очередь
От: _cb_  
Дата: 03.04.08 05:54
Оценка: :)
Здравствуйте, jazzer, Вы писали:

J>На каком лету, если можно обрабатывать только в правильном порядке, а его можно получить только получив и отсортировав все сообщения?


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

хотя возможно для вашей задачи все вышеописанное не нужно и сортировка прокатит...
Re[4]: [boost][mpl][variant] гетерогенная очередь
От: jazzer Россия Skype: enerjazzer
Дата: 03.04.08 08:47
Оценка: 3 (1)
Здравствуйте, _cb_, Вы писали:

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


J>>На каком лету, если можно обрабатывать только в правильном порядке, а его можно получить только получив и отсортировав все сообщения?


__>есть задачи в которых в принципе отсортировать по критерию (по времени например) нет возможности (например параллельная обработка сообщений в кластере). в подобных задачах сообщения не сортируют, а учитывают нужный критерий (время создания сообщения) в момент обработки. общих механизмов при в этом обычно не разрабатывают...

__>хотя возможно для вашей задачи все вышеописанное не нужно и сортировка прокатит...

в слове "учитывают" обычно собака и зарыта
На самом деле, целью моего поста не является обсуждение различных реализаций систем обработки сообщений — это слишком обширная тема и место ей не здесь, а в "Архитектуре".


Я ни в коем случае не утверждаю, что создал тут фреймворк на все времена.
Наоборот.
У меня была совершенно конкретная система, с которой я работал, и появилась совершенно конкретная задача, которую надо было решить, и ее удалось решить крайне просто и элегантно при помощи boost::mpl и boost::variant.


Просто о бусте бытует следующее представление:
1. Буст исключительно сложный
2. Некоторые библиотеки типа boost::mpl — с ними вообще простым смертным не разобраться
3. Чтобы использовать буст, надо вначале написать кучу трехэтажных шаблонов (особенно в случае boost::mpl), и как только ты их используешь, твой обычный код, который был бы без буста очень простым и коротким, теперь всегда будет горой шаблонов, текста будет в разы больше, и в основном нечитабельного.
4. Буст и особенно такие его части, как boost::mpl, простым прикладным программистам не нужны, они нужны только разработчикам библиотек.

Так вот целью моего поста было исключительно показать, что буста бояться не надо, даже таких страшных библиотек, как boost::mpl, и что при правильном применении они способны решать возникающие в жизни простого прикладного программиста задачи совсем без написания многоэтажных шаблонов и килобайтов кода, в котором полезной работой занимается всего одна строчка, а все остальные нужны только для того, чтоб всё вообще хоть как-то скомпилировалось и заработало (как я понимаю, этот "весь остальной код" называют модным словом boilerplate), и что код в результате получится прозрачный, понятный и простой, а старый код, который про буст ни сном ни духом, совершенно не пострадает.

В предлагаемом решении я вижу только одно место, которое можно отнести к boilerplate, т.е. которое ничего полезного не делает само по себе — это специализация оператора вызова функции для перехода от варианта к самим типам сообщений.
Все остальное служит для выражения определенных аспектов условия задачи (взятие определенного поля, упорядочение по определенному признаку в различных случаях).


А так, каждой задаче необходим свой подход, и не исключено, что если бы какое-то условие в задаче поменялось, я пришел бы в результате к совершенно другому решению.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: [boost][mpl][variant] гетерогенная очередь
От: _cb_  
Дата: 03.04.08 08:58
Оценка:
Здравствуйте, jazzer, Вы писали:

J>На самом деле, целью моего поста не является обсуждение различных реализаций систем обработки сообщений — это слишком обширная тема и место ей не здесь, а в "Архитектуре".


согласен. в рамках описанного решения действительно не стОит обсуждать обработку сообщений в целом.

J>У меня была совершенно конкретная система, с которой я работал, и появилась совершенно конкретная задача, которую надо было решить, и ее удалось решить крайне просто и элегантно при помощи boost::mpl и boost::variant.


и с этим согласен.
Re: [boost][mpl][variant] гетерогенная очередь
От: wtom  
Дата: 03.04.08 09:27
Оценка:

const int r = strcmp( get_time_field( left ), get_time_field( right ) );

потенциальная бага?
Не стоит переходить реку вброд, если известно только, что ее глубина (средняя) 4 фута.
Re[2]: [boost][mpl][variant] гетерогенная очередь
От: jazzer Россия Skype: enerjazzer
Дата: 03.04.08 10:59
Оценка:
Здравствуйте, wtom, Вы писали:

W>

W>

W>const int r = strcmp( get_time_field( left ), get_time_field( right ) );
W>

W>потенциальная бага?

API гарантирует, что поля, в которых лежит время (т.е. те, которые возвращает get_time_field), содержат строки одной длины в фиксированном формате, типа 2001-02-03-04:05:06.00007) (иначе их, очевидно, бессмысленно сравнивать через strcmp) и всегда оканчиваются нулем.

С учетом этой информации бага все еще есть?

P.S. Ну а если бы в этих полях лежало нечто несовместимое, то был бы какой-то тип, к которому все это можно привести (тот же time_t), и get_time_field возвращала бы его. Так что в этом смысле решение не изменилось бы.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: [boost][mpl][variant] гетерогенная очередь
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.04.08 13:32
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Просто о бусте бытует следующее представление:

J>1. Буст исключительно сложный
J>2. Некоторые библиотеки типа boost::mpl — с ними вообще простым смертным не разобраться
J>3. Чтобы использовать буст, надо вначале написать кучу трехэтажных шаблонов (особенно в случае boost::mpl), и как только ты их используешь, твой обычный код, который был бы без буста очень простым и коротким, теперь всегда будет горой шаблонов, текста будет в разы больше, и в основном нечитабельного.
J>4. Буст и особенно такие его части, как boost::mpl, простым прикладным программистам не нужны, они нужны только разработчикам библиотек.

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

Так вот у меня совсем другой список претензий к boost-у:

1. Реализация boost-а исключительно сложна. Ну т.е., когда все идет гладко и в исходники библиотеки заглядывать не нужно, то нет проблем. Но, тем не менее, здесь есть два момента, которые мне не нравятся:
— ни в одном другом языке (а мне приходилось лазить в библиотеки Ruby, Eiffel, D, немного Java) мне не приходилось видеть такой разительной разницы в сложности реализации библиотек и прикладных приложений. По мне, это некий признак того, что что-то где-то не так;
— всегда приятно иметь увереность в том, что твоих знаний хватает для того, чтобы при необходимости разобраться в деталях с происходящим в твоем приложении. По крайней мере у меня не было проблем с тем, чтобы залезть во внутренности MFC, Qt, FOX, ACE. В случае с boost ситуация обратная -- тот же boost.variant сразу же отбивает желание понять, как же он устроен.

2. Некоторые вещи в boost-е направлены на предоставление разработчику инструментов, которые, по хорошему, должны были быть в языке. Пример: boost.lambda. Да и, насколько я понимаю, boost.mpl так же использует различные трюки для того, чтобы обойти существующие недостатки языка. По-моему мнению, это не нормально. Должен развиваться язык, а недостатки языка не должны скрываться за библиотеками, сложность реализации которых слишком высока (см.предыдущий пункт).

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

4. Boost велик. Слишком велик. 22Mb в tar.bz2 версии 1.35 -- это занадто. Имхо, для C++ поздно создавать одну большую стандартную библиотеку. Можно понять Sun с JDK и MS с .NET Framework, которые держат большие штаты программистов, поддерживающих JDK/.NET Framework. А кто будет поддерживать OpenSource-ный boost? Что произойдет, если кому-то из авторов включенных в boost библиотек надоест сопровождать и развивать свое творение? Или как разработчикам каких-то библиотек выпускать новые релизы вне графика выхода версий самого boost-а?

Далее, включение библиотеки в boost осуществляется по результатам review, в которых, обычно, едва набирается несколько десятков отзывов. Т.е. заявляется что-нибудь типа boost.egg
Автор: Ka3a4oK
Дата: 03.04.08
и что? Находятся несколько ценителей прекрасного, которые присылают положительные review и egg в boost-е. И что из того, ценность буста повысилась? В то же время вне буста есть, например, crypto++, botan или cryptlib, которыми пользуются сотни, если не тысячи программистов, но которые никаким боком к boost-у не относятся.

Еще один момент. Библиотеки, которые являются альтернативными boost-овским, они что, уже второго сорта? Бустовская сериализация -- она лучше, чем s11n? Бустовские регулярные выражения лучше, чем PCRE? Бустовские юнит-тесты намного лучше CppUnit? Не получится ли так, что когда разработчику понадобиться что-то, то он просто возмет реализацию из boost-а даже не глядя на альтернативы? Т.е. выбор будет строится не на возможностях, а на репутации. Как бы в результате boost не стал монополистом, который своей массой будет просто давить конкурентов.


Вот такое, собственно говоря, имхо.
Не то, чтобы я принципиально отказывался от использования boost-а по каким-то религиозным соображениям. У меня даже часть старых проектов использует boost.unit для юнит-тестов. Или если мне потребуется boost.multi_index, то я возьму boost. Но сделаю это несколько скрепя сердцем, поскольку boost просто не является библиотекой, которая мне нравится (в отличии, например, от PCRE, Qt, FOX, ACE, Crypto++ и иже с ними).

К читателям: не думаю, что нужно начитать флейм по этому поводу. Я описал весь этот текст для того, чтобы у jazzer-а не сложилось превратного впечатления о том, в чем же я лично обвиняю boost.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[6]: [boost][mpl][variant] гетерогенная очередь
От: Alxndr Германия http://www.google.com/profiles/alexander.poluektov#buzz
Дата: 03.04.08 14:10
Оценка:
Здравствуйте, eao197, Вы писали:

E>Еще один момент. Библиотеки, которые являются альтернативными boost-овским, они что, уже второго сорта? Бустовская сериализация -- она лучше, чем s11n? Бустовские регулярные выражения лучше, чем PCRE? Бустовские юнит-тесты намного лучше CppUnit? Не получится ли так, что когда разработчику понадобиться что-то, то он просто возмет реализацию из boost-а даже не глядя на альтернативы? Т.е. выбор будет строится не на возможностях, а на репутации. Как бы в результате boost не стал монополистом, который своей массой будет просто давить конкурентов.


Не понять тебя.

Ты же первый говоришь, что хотел бы видеть (по крайней мере) некоторые из этих вещей в стандартной библиотеке, нет?
Стандартная библиотека при таких рассуждениях тоже становится монополистом.
Является ли это аргументом против стандартной библиотеки?
Re[6]: [boost][mpl][variant] гетерогенная очередь
От: Alxndr Германия http://www.google.com/profiles/alexander.poluektov#buzz
Дата: 03.04.08 14:14
Оценка:
Здравствуйте, eao197, Вы писали:

E>2. Некоторые вещи в boost-е направлены на предоставление разработчику инструментов, которые, по хорошему, должны были быть в языке. Пример: boost.lambda. Да и, насколько я понимаю, boost.mpl так же использует различные трюки для того, чтобы обойти существующие недостатки языка. По-моему мнению, это не нормально. Должен развиваться язык, а недостатки языка не должны скрываться за библиотеками, сложность реализации которых слишком высока (см.предыдущий пункт).


Т.е. рано или поздно любая фича должна быть добавлена в язык?
Re[7]: [boost][mpl][variant] гетерогенная очередь
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.04.08 14:26
Оценка: :)
Здравствуйте, Alxndr, Вы писали:

E>>2. Некоторые вещи в boost-е направлены на предоставление разработчику инструментов, которые, по хорошему, должны были быть в языке. Пример: boost.lambda. Да и, насколько я понимаю, boost.mpl так же использует различные трюки для того, чтобы обойти существующие недостатки языка. По-моему мнению, это не нормально. Должен развиваться язык, а недостатки языка не должны скрываться за библиотеками, сложность реализации которых слишком высока (см.предыдущий пункт).


A>Т.е. рано или поздно любая фича должна быть добавлена в язык?


Нет. Любая фича должна быть реализована в виде библиотеки и включена в boost. И лишь после 7-8 лет ее использования она должна войти в очередной драфт стандарта.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[7]: [boost][mpl][variant] гетерогенная очередь
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.04.08 14:30
Оценка:
Здравствуйте, Alxndr, Вы писали:

A>Ты же первый говоришь, что хотел бы видеть (по крайней мере) некоторые из этих вещей в стандартной библиотеке, нет?


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

A>Стандартная библиотека при таких рассуждениях тоже становится монополистом.

A>Является ли это аргументом против стандартной библиотеки?

Тут недавно была дискусия
Автор: jazzer
Дата: 26.03.08
о том, что разработка интераторов для сложных структур данных была бы проще и эффективнее, если бы вместо пары итераторов [begin, end) стандартные алгоритмы использовали бы range. Что может служить примером того, как зафиксированные намертво в стандарте решения приводят к непредвиденным сложностям в последствии.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[8]: [boost][mpl][variant] гетерогенная очередь
От: Alxndr Германия http://www.google.com/profiles/alexander.poluektov#buzz
Дата: 03.04.08 14:49
Оценка:
Здравствуйте, eao197, Вы писали:

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


A>>Ты же первый говоришь, что хотел бы видеть (по крайней мере) некоторые из этих вещей в стандартной библиотеке, нет?


E>Не помню, чтобы я говорил про стандартную библиотеку.


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

E>Некоторые вещи должны быть частью языка (т.е. поддерживаться компилятором), а не библиотеками.


Зачем ты поскипал приводимый отбой же пример библиотек? Регулярные выражения, сериализация — разве это должно быть встроено в язык? С другой стороны, разве это не хотелось бы видеть частью стандартной библиотеки?
Re[9]: [boost][mpl][variant] гетерогенная очередь
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.04.08 14:59
Оценка:
Здравствуйте, Alxndr, Вы писали:

A>>>Ты же первый говоришь, что хотел бы видеть (по крайней мере) некоторые из этих вещей в стандартной библиотеке, нет?


E>>Не помню, чтобы я говорил про стандартную библиотеку.


A>Я говорю о библиотеках предметной области. Мне казалось, что я нередко видел твои рассуждения, ставящие в минус языку черезчур большой выбор библиотек для каждой предметной области


Ну, мое мнение с декабря 2006 не очень изменилось. Я по прежнему сторонник описанного здесь мной варианта
Автор: eao197
Дата: 28.12.06
. Хотя сейчас мне больше нравится идея систему управления пакетами типа RubyGems или Maven2 (хотя с последним я знаком очень поверхностно).

E>>Некоторые вещи должны быть частью языка (т.е. поддерживаться компилятором), а не библиотеками.


A>Зачем ты поскипал приводимый отбой же пример библиотек? Регулярные выражения, сериализация — разве это должно быть встроено в язык? С другой стороны, разве это не хотелось бы видеть частью стандартной библиотеки?


Регулярные выражения -- это вопрос, нужны ли они в std или нет. Но ответ на него уже дан.
А вот сериализация -- это явно для для std, имхо.


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