Как можно было недавно убедиться, написанный с использованием SObjectizer код бывает многословным. Хотя работа в направлении уменьшения многословности ведется постоянно, процесс этот идет не быстро. Как раз тот случай, когда "простота не предшествует сложности, а следует за ней" ((с) Алан Перлис).
Время требуется на то, чтобы на своем опыте прочувствовать, что какая-то операция требует слишком большой писанины. Потом требуется время, чтобы в голову пришло подходящее решение. Потом -- чтобы это решение было воплощено, протестировано, задокументировано и вошло в релиз. Вроде бы нигде ничего сложного, но появление новых полезных фич иногда растягивается на месяцы.
Тем не менее, процесс идет. И ниже один из примеров в качестве подтверждения.
В декабре 2013-го в версии 5.2.3 в SO-5 из SO-4 была повзаимствована поддержка "дочерних коопераций". Т.е. кооперацию агентов можно было подчинить другой кооперации, родительской. И SO-5 гарантировал, что дочерняя кооперация гарантированно завершит свою работу раньше родительской. В C++, где всеми ресурсами программист управляет вручную, это очень полезная гарантия. Ну да не суть. Суть в том, как программист должен был написать создание дочерней кооперации внутри какого-то из агентов родительской кооперации. Выглядело это так:
void parent_agent::so_evt_start() override { // Создание экземпляра кооперации и назначение ей родителя. // У кооперации должно быть уникальное имя. Создаем его на // основе имени родительской кооперации. auto coop = so_environment().create_coop( so_coop_name() + "/child" ); coop->set_parent_coop_name( so_coop_name() ); // Наполнение кооперации. coop->add_agent( new first_child_agent( so_environment(), some_params() ) ); coop->add_agent( new second_child_agent( so_environment(), some_params() ) ); // Регистрация. so_environment().register_coop( std::move( coop ) ); } |
Прошло довольно много времени, и в октябре 2014-го года в версии 5.5.1 произошло первое небольшое улучшение -- добавлена возможность автоматической генерации имен для коопераций. Т.е. если пользователю имя кооперации не нужно для каких-то своих целей (например, для логирования или мониторинга), то можно поручить SO-5 выдумывание новых имен. Уже стало чуть попроще:
void parent_agent::so_evt_start() override { // Создание экземпляра кооперации и назначение ей родителя. // Про имя кооперации не думаем. auto coop = so_environment().create_coop( so_5::autoname ); coop->set_parent_coop_name( so_coop_name() ); // Наполнение кооперации. coop->add_agent( new first_child_agent( so_environment(), some_params() ) ); coop->add_agent( new second_child_agent( so_environment(), some_params() ) ); // Регистрация. so_environment().register_coop( std::move( coop ) ); } |
Т.к. дочерние кооперации -- штука удобная и практичная, пользоваться ей доводилось все чаще и чаще, поэтому объем писанины хотелось сократить еще больше. Очередной шажок в этом направлении происходит в феврале 2015-го в версии 5.5.3, в которой добавляется вспомогательная функция create_child_coop:
void parent_agent::so_evt_start() override { // Создание экземпляра кооперации и назначение ей родителя. // Про имя кооперации не думаем. auto coop = so_5::rt::create_child_coop( *this, so_5::autoname ); // Наполнение кооперации. coop->add_agent( new first_child_agent( so_environment(), some_params() ) ); coop->add_agent( new second_child_agent( so_environment(), some_params() ) ); // Регистрация. so_environment().register_coop( std::move( coop ) ); } |
Кода стало всего на одну строку меньше, но это важная строка -- про нее иногда забываешь и новая кооперация оказывается без родителя, после чего где-нибудь в другом месте программы могут возникать, а могут и не возникать сбои при работе с ресурсами вроде коннектов к БД. Поэтому работа через create_child_coop надежнее, нет возможности ошибиться и забыть вызвать set_parent_coop_name().
В версии 5.5.4, вышедшей буквально на днях, появился метод make_agent, который позволяет компактнее записывать создание экземпляров агентов. Так что код еще чуть-чуть подсократился:
void parent_agent::so_evt_start() override { // Создание экземпляра кооперации и назначение ей родителя. // Про имя кооперации не думаем. auto coop = so_5::rt::create_child_coop( *this, so_5::autoname ); // Наполнение кооперации. coop->make_agent< first_child_agent >( some_params() ); coop->make_agent< second_child_agent >( some_params() ); // Регистрация. so_environment().register_coop( std::move( coop ) ); } |
Но и этот вариант не самый простой и надежный, т.к. редко, но бывает, что забываешь вызвать register_coop и зарегистрировать полностью подготовленную новую кооперацию. Ошибка эта, к счастью, намного быстрее обнаруживается. Но, все же, хотелось и ее устранить.
Поэтому в разрабатывающейся сейчас версии 5.5.5 добавлена еще одна вспомогательная функция introduce_child_coop, которая позволяет записать ту же самую операцию вот так:
void parent_agent::so_evt_start() override { // Создание экземпляра кооперации и назначение ей родителя. // Про имя кооперации не думаем. // Кооперация регистрируется сразу же после завершения создания. so_5::rt::introduce_child_coop( *this, [this]( so_5::rt::agent_coop_t & coop ) { // Наполнение кооперации. coop.make_agent< first_child_agent >( some_params() ); coop.make_agent< second_child_agent >( some_params() ); } } |
Ну или для того, чтобы разница была заметна еще лучше, варианты для версий 5.2.3 и 5.5.5 с выброшенными комментариями:
// v.5.2.3 void parent_agent::so_evt_start() override { auto coop = so_environment().create_coop( so_coop_name() + "/child" ); coop->set_parent_coop_name( so_coop_name() ); coop->add_agent( new first_child_agent( so_environment(), some_params() ) ); coop->add_agent( new second_child_agent( so_environment(), some_params() ) ); so_environment().register_coop( std::move( coop ) ); } // v.5.5.5 void parent_agent::so_evt_start() override { so_5::rt::introduce_child_coop( *this, [this]( so_5::rt::agent_coop_t & coop ) { coop.make_agent< first_child_agent >( some_params() ); coop.make_agent< second_child_agent >( some_params() ); } } |
Между двумя этими фрагментами полтора года развития фреймворка. Можно ли было получить вариант с introduce_child_coop намного раньше? И да, и нет.
Да, потому, что я далеко не самый хороший и изобретательный программист, до меня слишком долго доходит, и у меня довольно много терпения, чтобы писать много кода. Так что будь на моем месте человек чуток более смышленный и, в хорошем смысле, ленивый разработчик, все это появилось бы пораньше.
А нет потому, что для воплощения идей нужны инструменты. Пока нужно было поддерживать MSVS2012, в котором variadic templates не было, написание make_agent и introduce_child_coop было бы намного, намного сложнее. Но когда от поддержки MSVS2012 отказались, горизонт возможностей расширился, что и позволило добавить несколько полезных шаблонных методов и функций для облегчения жизни разработчика.
Да, собственно, чего далего за примерами ходить. Если выйти за рамки C++11, то в C++14 создание дочерней кооперации будет требовать еще меньше кода, т.к. там есть полиморфные лямбды и вызов introduce_child_coop можно буде записать вот так:
void parent_agent::so_evt_start() override { so_5::rt::introduce_child_coop( *this, [this]( auto & coop ) { coop.make_agent< first_child_agent >( some_params() ); coop.make_agent< second_child_agent >( some_params() ); } } |
Так что процесс идет. Не быстро, но идет.
PS. Ну и повторюсь еще раз. С++11 -- это уже совсем другой язык, который поднимает разработку на С++ на совсем другой уровень. Проверенно на людях ;)
Комментариев нет:
Отправить комментарий