На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: Qraizer
Страницы: (14) 1 2 [3] 4 5 ...  13 14 все  ( Перейти к последнему сообщению )  
> SObjectizer 5.3.0
    Цитата eao197 @
    Это констатация того, что в libcppa сделали то, что в SO вообще никогда не пытались сделать.

    Блин, очевидные вещи всегда сложнее всего заметить о описать.

    Вот еще какая штука. В Erlang-е нет никаких других механизмов структурирования информации, кроме туплов. Т.е. есть лишь туплы для структурирования и list-ы и (вроде как с недавних пор) map-ы для агрегирования. Все.

    Но в туплах отдельные элементы не имеют своих имен, поэтому для доступа к элементу тупла нужен какой-то механизм. В плюсовых реализациях туплов -- это, например, методы get<INDEX>. А в языках, которые нормально затачивались под работу с туплами, как в Erlang, используется pattern matching. Отсюда же вытекает и формат receive в Erlang-е: если процессу отослали какую-то структуру данных, то это будет или тупл, или list/map. А, поскольку к данным в тупле нужно как-то добраться, то отсюда и паттерн-матчинг как селектор сообщения. (Аналогичным образом и работа с list/map-ами через паттерн-матчинг, ведь язык функциональный, циклов вроде for в нем нет, поэтому обход коллекций записывается как рекурсия с разбором контейнера на head и tail через паттерн-матчинг).

    Однако, туплы автоматически означают структурную эквивалентность. Т.е. если у меня есть {0,1} и {3,5}, то я не могу судить -- относятся ли эти значения к экземплярам разных типов или нет. Может быть первый обозначает IP-адрес и порт, а второй секунды и микросекунды?

    Для решения этой проблемы в Erlang-е ввели дискриминанты под названием атомы. Что стало позволять записывать туплы с указанием "типовой принадлежности": {address, 0, 1} и {timeval, 3, 5}.

    Однако, в императивных языках, вышедших из Aglol/Simula, нет необходимости в таком отдельном дискриминанте таковым там является само имя типа. Т.е. то, что в Erlang-е из-за наличия в языке struct записывается как {address, 0, 1}, в C++ записывается как address(0, 1).

    Соответственно, значение паттерн-матчинга в C++ ниже, чем в Erlang. Ведь в Erlang-е для разбора значения {address, 0, 1} нам нужно писать образец с присваиванием значений локальным константам:
    ExpandedWrap disabled
      process_address({address, Host, Port}) ->
        что-то там с использованием Host и Port

    А в С++ мы просто обращаемся к полям структуры:
    ExpandedWrap disabled
      process_address(const address & a ) {
        // что-то там с использованием a.host и a.port.
      }

    Добавим сюда еще и то, что Erlang -- это динамически типизированный язык. Это означает, что код на Erlang-е получается компактнее, обозримее и, в некоторых случаях, он сразу становится "обобщенным". Т.е. может работать с разными типами аргументов. Например, если какой-то фрагмент Erlang-овской программы использует туплы вида {address, Host, Port}, то ему может оказаться без разницы, что из себя представляет Host -- uint32, string или ipv6. Это ведет к двум важным последствиям в Erlang-е: сокращается объем кода и код оказывается толерантным к изменениям типов элементов тупла. Т.е. сначала process_address успешно работал с представлением Host в виде unit32 и string, а затем спокойно пережил еще и добавление ipv6.

    В статически-типизированном C++ этот фокус не работает. Писать в любом случае приходится больше (спецификация типов аргументов). Толерантность к изменению типов элементов тупла нужно обеспечивать за счет использования шаблонов, а в этом так же есть свои минусы. Да и просто вариант
    ExpandedWrap disabled
      struct address {
        какой-то-тип host;
        short port;
      }

    в котором на месте "какой-то-тип" может быть как unit32, так и std::string, так и ipv6, в C++ уже потребует каких-то фокусов (вроде задействования какого-то из variant-ов) с соответствующими последствиями (например, накладными расходами в run-time).

    Поэтому мне и показалось странным копирование подхода из Erlang-а в C++ную библиотеку. Родные и удобные для Erlang-а вещи смотрятся для меня как чужеродные в C++. Например, мне не понятно, чем вот это:
    ExpandedWrap disabled
      on(atom("add"), arg_match) >> [](int a, int b) { /*...*/ },
      on(atom("multiply"), arg_match) >> [](int a, int b) { /*...*/ },

    лучше, чем вот это:
    ExpandedWrap disabled
      struct add { int a, int b };
      struct multiply { int a, int b };
       
      on( arg_match ) >> []( const add & w ) { /* ... */ },
      on( arg_match ) >> []( const multiply & w ) { /* ... */ }

    Ведь здесь мы получаем защиту статической типизации. Никто не сможет просто так отослать сообщение multiply, передав в качестве аргументов две строки. Или написав по ошибке atom("multiplicate") вместо atom("multiply").
    Сообщение отредактировано: eao197 -
      Цитата eao197 @
      Но со временем мы от этого ушли в сторону более мощной системы сериализации. А так же и поменяли подход к построению распределенных приложений на основе SO. Сейчас этими вещами занимается mbapi_4 (для сериализации используется ObjESSty -- что-то вроде Protobuf-а). Но, поскольку mbapi_4 -- это всего лишь т.н. layer, коих на SO можно навесить несколько, то вместо mbapi_4 можно сделать обмен сообщениями посредством AMQP и Protobuf-а.

      Protobuf и свой сериализатор.
      Цитата eao197 @
      Потому, что мы по другому подходили к организации взаимодействия агентов. Агент A должен отослать агенту B какое-то осмысленное сообщение, например, "влючить лампочку" или "остановить двигатель". Соответственно, сообщение должно быть описано типом.

      Ok, я хочу enum ;)
      Цитата eao197 @
      А, поскольку мы уже заставляем пользователя вводить тип сообщения, то с точки зрения ООП естественным образом напрашивается его наследование от чего-нибудь.

      В вашем примере нет ООП (или вы его не показали). Потому что для пользователя нет никакого профита от наследования - по вашим словам, это лишь артефакт реализации.
      Цитата eao197 @
      Я пока не совсем понял, что там с состояниями у акторов libcppa. Поэтому не могу сейчас ответить. Если укажете конкретный пример, который бы вам было бы интересно увидеть переписанным на SO, я постараюсь это сделать.

      Ну, я имел в виду fixed_stack. Или обедающих философов. Там обработка сообщений зависит от состояния актора, причём код структурирован по состояниям. Вот аналог этого и хотелось бы увидеть.
      По поводу оставления сообщений в ящике, наверное, я что-то напутал. Сейчас читаю, что не сопоставленные сообщения отбрасываются. Странно, надо будет уточнить. Кстати, как с этим в SO?
      Цитата eao197 @
      Мне не нравится то, что в C++ 1-в-1 перенесли механизм из Erlang-а, польза от которого в C++ очень сомнительна. Это то, про что Страуструп говорит, как о попытке использования не подходящих к языку приемов.

      Здесь нарушена причинно-следственная связь. Т.е. не доказано, что это именно тот случай, о котором говорит Бьярн. Читающему предлагается поверить вам на слово, а между тем я не вижу в данном случае "неподходящих к языку приёмов".
      Кстати, о Страуструпе. ЕМНИП, на вопрос, а почему нет требования наследовать исключения от std::exception, он отвечает "а зачем?".
      Цитата eao197 @
      Как в свое время пытались делать библиотеки контейнеров для C++, требуя, чтобы все элементы контейнера были унаследованы от какого-нибудь общего Object-а

      Там как раз были виноваты любители ООП :D Они хотели положить в контейнеры именно полиморфные типы. В их представлении не было жизни за пределами ООП. Да и большая часть таких библиотек появилась ещё до шаблонов.
      А вообще интрузивные контейнеры полезны - да хотя бы документацию boost.intrusive почитайте. Например, благодаря их особенностям, lock-free структуры данных легче делать именно интрузивными.
      Так что это не является чем-то неправильным, это лишь иной подход с плюсами и минусами.
      Цитата eao197 @
      Скорее это просто попытка сравнить отбойный молоток с дрелью. Вроде как дырки оба инструмента позволяют делать...

      Я не вижу здесь разных инструментов - с помощью libcppa можно писать в том же стиле, что и с SO. Так что это дрель рядом с перфоратором с режимом дрели :crazy:

      Добавлено
      Цитата eao197 @
      Добавим сюда еще и то, что Erlang -- это динамически типизированный язык

      Цитата eao197 @
      В статически-типизированном C++ этот фокус не работает

      Время типизации здесь ни при чём. Дело в синтаксисе - явная/неявная. Хиндли-Милнер сделает код статически типизированного языка не менее компактным.
      Цитата eao197 @
      Поэтому мне и показалось странным копирование подхода из Erlang-а в C++ную библиотеку. Родные и удобные для Erlang-а вещи смотрятся для меня как чужеродные в C++. Например, мне не понятно, чем вот это:
      ...
      лучше, чем вот это:

      Почему "лучше"? Это другая возможность. libcppa не исключает ни одну из них.

      Добавлено
      Ну, и да, в Erlang всё же есть структуры... но они преобразуются в тегированные кортежи, да.

      Добавлено
      Цитата korvin @
      Возможно в этом нет необходимости.

      Не, здесь есть необходимость :D
        Цитата eao197 @
        Но с точки зрения какой-то абстрактной теоритической чистоты, возможно, в наследовании от общей базы есть что-то нехорошее.

        Дело не в хорошести/нехорошести, а в надобности/ненадобности. Из одного только факта использования ООП никаким образом не вытекает необходимость наследования. Но это все так, к слову.
          Цитата MyNameIsIgor @
          Цитата eao197 @
          Потому, что мы по другому подходили к организации взаимодействия агентов. Агент A должен отослать агенту B какое-то осмысленное сообщение, например, "влючить лампочку" или "остановить двигатель". Соответственно, сообщение должно быть описано типом.

          Ok, я хочу enum ;)

          Я понимаю, что вы можете хотеть работать с туплами вида <lamp_on, power_level> или <engine_off, mode, timeout>.
          Но не понимаю, зачем это делать на практике, если можно работать со структурами struct lamp_on{int power_level;} или struct engine_off{management_mode mode; duration timeout;}.

          Имхо, совершенно разные подходы. Если кому-то нравится первый подход, пусть работает с инструментом, который этот подход поддерживает. Мне больше нравится второй подход, соответственно и инструмент такой.

          Цитата MyNameIsIgor @
          Цитата eao197 @
          А, поскольку мы уже заставляем пользователя вводить тип сообщения, то с точки зрения ООП естественным образом напрашивается его наследование от чего-нибудь.

          В вашем примере нет ООП (или вы его не показали). Потому что для пользователя нет никакого профита от наследования - по вашим словам, это лишь артефакт реализации.

          А какой профит пользователям Qt наследоваться от QObject-а?

          Цитата MyNameIsIgor @
          Цитата eao197 @
          Я пока не совсем понял, что там с состояниями у акторов libcppa. Поэтому не могу сейчас ответить. Если укажете конкретный пример, который бы вам было бы интересно увидеть переписанным на SO, я постараюсь это сделать.

          Ну, я имел в виду fixed_stack. Или обедающих философов. Там обработка сообщений зависит от состояния актора, причём код структурирован по состояниям. Вот аналог этого и хотелось бы увидеть.

          Ну, fixed_stack выглядел бы вот так:
          ExpandedWrap disabled
            class fixed_stack : public so_5::rt::agent_t
            {
              const so_5::rt::mbox_ref_t m_mbox;
              so_5::rt::state_t st_empty;
              so_5::rt::state_t st_filled;
              so_5::rt::state_t st_full;
             
              const size_t m_max_size;
              std::vector< int > m_stack;
             
            public :
              fixed_stack( so_5::rt::environment_t & env,
                const so_5::rt::mbox_ref_t & mbox,
                size_t max_size )
                : so_5::rt::agent_t( env )
                , m_mbox( mbox )
                , st_empty( so_self_ptr(), "empty" )
                , st_filled( so_self_ptr(), "filled" )
                , st_full( so_self_ptr(), "full" )
                , m_max_size( max_size )
                {}
             
              struct msg_push : public so_5::rt::message_t
              {
                int m_val;
              };
              struct msg_pop : public so_5::rt::signal_t {};
             
              virtual void
              so_define_agent()
              {
                so_change_state( st_empty );
             
                so_subscribe( m_mbox ).in( st_empty ).in( st_filled ).event(
                  [this]( const msg_push & w ) {
                    m_stack.push_back( w.m_val );
                    if( m_stack.size() == m_max_size )
                      so_change_state( st_full );
                  } );
             
                so_subscribe( m_mbox ).in( st_filled ).in( st_full ).event( so_5::signal< msg_pop >,
                  [this]() {
                    auto r = m_stack.back();
                    m_stack.pop_back();
                    so_change_state( m_stack.empty() ? st_empty : st_filled );
                    return r;
                  } );
             
                so_subscribe( m_mbox ).in( st_empty ).event( so_5::signal< msg_pop >,
                  []() {
                    throw std::runtime_error( "empty_stack" );
                  } );
              }
            };


          Цитата MyNameIsIgor @
          По поводу оставления сообщений в ящике, наверное, я что-то напутал. Сейчас читаю, что не сопоставленные сообщения отбрасываются. Странно, надо будет уточнить. Кстати, как с этим в SO?

          Не обработанные сообщения выбрасываются. Selective receive нет и, полагаю, не будет.

          Цитата MyNameIsIgor @
          Цитата eao197 @
          Мне не нравится то, что в C++ 1-в-1 перенесли механизм из Erlang-а, польза от которого в C++ очень сомнительна. Это то, про что Страуструп говорит, как о попытке использования не подходящих к языку приемов.

          Здесь нарушена причинно-следственная связь. Т.е. не доказано, что это именно тот случай, о котором говорит Бьярн. Читающему предлагается поверить вам на слово, а между тем я не вижу в данном случае "неподходящих к языку приёмов".

          А разве такие вещи могут быть доказаны? Здесь больше дело вкуса. Если кому-то нравится полагаться на строковые константы длиной до 10 символов и ручной разбор туплов на составляющие -- ну значит для него это подходящий прием. Если кому-то, как и мне, это не нравится, то для меня не подходящий.

          Цитата MyNameIsIgor @
          Цитата eao197 @
          Добавим сюда еще и то, что Erlang -- это динамически типизированный язык

          Цитата eao197 @
          В статически-типизированном C++ этот фокус не работает

          Время типизации здесь ни при чём. Дело в синтаксисе - явная/неявная. Хиндли-Милнер сделает код статически типизированного языка не менее компактным.

          Мы же говорим о переносе принципов работы Erlang-а в C++, а не в OCaml или Haskell. Поэтому более чем при чем.

          Цитата MyNameIsIgor @
          Почему "лучше"? Это другая возможность. libcppa не исключает ни одну из них.

          Ок, поинт я понял. Значит можно сказать, что SObjectizer помещает пользователя в более жесткие рамки.

          Цитата MyNameIsIgor @
          Добавлено
          Ну, и да, в Erlang всё же есть структуры... но они преобразуются в тегированные кортежи, да.

          Ссылочку можно?

          Цитата MyNameIsIgor @
          Добавлено
          Цитата korvin @
          Возможно в этом нет необходимости.

          Не, здесь есть необходимость :D

          В итоге, если устранить все ошибки и записать код примера на C++ полностью, то по объему он уйдет не сильно далеко от SO-варианта. Что до сложности, то любой инструмент нуждается в изучении. После определенного порога он перестает быть сложным.
            Кстати, eao197, код без кучи переносов строк выглядит приятнее. А, korvin?
              Цитата eao197 @
              Я понимаю, что вы можете хотеть работать с туплами вида <lamp_on, power_level> или <engine_off, mode, timeout>.
              Но не понимаю, зачем это делать на практике, если можно работать со структурами struct lamp_on{int power_level;} или struct engine_off{management_mode mode; duration timeout;}.

              Я вам привёл весьма жизненный пример - я хочу послать сообщения типа enum, благо теперь есть enum class. Как мне это сделать в SO? Это риторический вопрос ;)
              Я не понимаю, зачем мне писать
              ExpandedWrap disabled
                struct msg_1 : message_t {};
                struct msg_2 : message_t {};
                ...
                struct msg_n : message_t {};

              вместо
              ExpandedWrap disabled
                enum class msg
                {
                  msg_1,
                  msg_2,
                  ...
                  msg_n
                };

              Цитата eao197 @
              А какой профит пользователям Qt наследоваться от QObject-а?

              А это тоже артефакт реализации. Но там хоть много чего можно переопределять типа обработки событий.
              Цитата eao197 @
              А разве такие вещи могут быть доказаны? Здесь больше дело вкуса. Если кому-то нравится полагаться на строковые константы длиной до 10 символов и ручной разбор туплов на составляющие -- ну значит для него это подходящий прием. Если кому-то, как и мне, это не нравится, то для меня не подходящий.

              Замечательно. libcppa позволяет оба подхода. Почему же не конкурент?
              Цитата eao197 @
              Мы же говорим о переносе принципов работы Erlang-а в C++, а не в OCaml или Haskell. Поэтому более чем при чем.

              ... Ещё раз: код на C++ менее компактный не из-за статической, а из-за явной типизации.
              Цитата eao197 @
              Ссылочку можно?

              Эмм.. Ну, [Чезарини, Томпсон "Программирование в Erlang"]. Есть пара строк в вики.
              Цитата eao197 @
              В итоге, если устранить все ошибки и записать код примера на C++ полностью, то по объему он уйдет не сильно далеко от SO-варианта.

              Во-первых, дело не в объёме, а в том, что korvin назвал "адовостью" :) Да, читаемость - вещь субъективная, но тут я с ним согласен: примеры на SO нечитаемы.
              Во-вторых, смысл boost.fibers в другом - в возможности писать синхронный код вместо лапшеколбэков.

              Добавлено
              Ах, да, ещё забыл. У вас группировка состояний по одному обработчику
              ExpandedWrap disabled
                so_subscribe( m_mbox ).in( st_empty ).in( st_filled ).event

              Это неинтересно, ибо редко обработчик один для разных состояний. Интереснее как в случае философов - группировка обработчиков по одному состоянию.
              Сообщение отредактировано: MyNameIsIgor -
                ExpandedWrap disabled
                  enum class msg
                  {
                    msg_1,
                    msg_2,
                    ...
                    msg_n
                  };
                   
                  template <msg V> struct msg2type {}: message_t;
                Ужас, да?
                  Цитата MyNameIsIgor @
                  Я не понимаю, зачем мне писать
                  ExpandedWrap disabled
                    struct msg_1 : message_t {};
                    struct msg_2 : message_t {};
                    ...
                    struct msg_n : message_t {};

                  вместо
                  ExpandedWrap disabled
                    enum class msg
                    {
                      msg_1,
                      msg_2,
                      ...
                      msg_n
                    };

                  Потому, что в подавляющем большинстве случаев с сообщением связаны еще и какие-то данные. Т.о., при реальной работе вам кроме enum class msg с вариантами msg_1,...,msg_n предстоит вести дополнительные наборы структур или туплов.
                  Цитата MyNameIsIgor @
                  Цитата eao197 @
                  А какой профит пользователям Qt наследоваться от QObject-а?

                  А это тоже артефакт реализации.

                  Ну вот и у нас аналогично. Всех особенностей реализации не спрячешь. У нас вот здесь пользователь видит некоторые ограничения. Что позволяет чуть более эффективно работать с сообщениями, чем это было в SO-4, где таких ограничений не было.
                  Цитата MyNameIsIgor @
                  Замечательно. libcppa позволяет оба подхода. Почему же не конкурент?

                  Знаете, я когда-то задал вопрос Мартину Одерски о том, что он думает о конкурентах Scala (вроде Nemerle, F#, Nice и пр.). Он тогда высказался, что не считает эти языки конкурентами, скорее они все помогают друг другу развиваться и набирать популярность.

                  Вот так и здесь. Мне не суть важно, насколько libcppa и SObjectizer конкурируют друг с другом. Намного важнее то, оставляют ли они C++ разработчиков в рамках C++ или же люди все-таки уходят в Erlang, Scala или еще куда-нибудь. Берут какую-нибудь Akka, а потом узкие места пытаются переписать на C или начинают бороться с GC. Тогда как можно было получить более качественный результат в C++.

                  Цитата MyNameIsIgor @
                  Цитата eao197 @
                  Мы же говорим о переносе принципов работы Erlang-а в C++, а не в OCaml или Haskell. Поэтому более чем при чем.

                  ... Ещё раз: код на C++ менее компактный не из-за статической, а из-за явной типизации.

                  Ок, понял. Похоже, суть разногласий здесь в том, что под "статической типизацией" я сразу подразумевал и статическую типизацию и явную декларацию типов.

                  Цитата MyNameIsIgor @
                  Цитата eao197 @
                  В итоге, если устранить все ошибки и записать код примера на C++ полностью, то по объему он уйдет не сильно далеко от SO-варианта.

                  Во-первых, дело не в объёме, а в том, что korvin назвал "адовостью" :) Да, читаемость - вещь субъективная, но тут я с ним согласен: примеры на SO нечитаемы.
                  Во-вторых, смысл boost.fibers в другом - в возможности писать синхронный код вместо лапшеколбэков.

                  Суть в том, что SO никогда, т.е. вообще никогда, не задумывался для написания синхронного кода. Добавленная в 5.3 фича -- это эксперимент, на результат которого нужно будет еще посмотреть.
                  ---
                    Цитата Qraizer @
                    Кстати, eao197, код без кучи переносов строк выглядит приятнее.

                    А как бы вы пример отформатировали?
                      Цитата MyNameIsIgor @
                      Это неинтересно, ибо редко обработчик один для разных состояний. Интереснее как в случае философов - группировка обработчиков по одному состоянию.

                      Никто не заставляет писать один обработчик на насколько состояний, можно делать кучу отдельных subscribe. Но, если можно объединить, то можно объединить.

                      Про философов посмотрю. Нужно вкурить особенности тамошней реализации.
                        Цитата eao197 @
                        Потому, что в подавляющем большинстве случаев с сообщением связаны еще и какие-то данные. Т.о., при реальной работе вам кроме enum class msg с вариантами msg_1,...,msg_n предстоит вести дополнительные наборы структур или туплов.

                        Ну, а можно это буду решать я как пользователь?
                        Цитата eao197 @
                        Ну вот и у нас аналогично. Всех особенностей реализации не спрячешь.

                        Сложностей, которые принёс бы отказ от QObject, несравнимо больше сложностей, которые появятся от отказа наследования для типа сообщения. Да я вообще никаких особых сложностей от произвольного типа не вижу. Да и у вас это уже было. А отказываться только из-за неудобства разработчиков... ну, библиотеки пишутся для удобства пользователей, а не создателей.
                        Цитата eao197 @
                        Мне не суть важно, насколько libcppa и SObjectizer конкурируют друг с другом. Намного важнее то, оставляют ли они C++ разработчиков в рамках C++ или же люди все-таки уходят в Erlang, Scala или еще куда-нибудь. Берут какую-нибудь Akka, а потом узкие места пытаются переписать на C или начинают бороться с GC. Тогда как можно было получить более качественный результат в C++.

                        А, простите, вы уже где-то показали, что ваш результат качественнее, кроме "я так считаю"? :) Какие, кстати, критерия качества?
                        Цитата eao197 @
                        Про философов посмотрю. Нужно вкурить особенности тамошней реализации.

                        Ну, меня интересует не программа с точно такой же семантикой, а просто аналог конструкций
                        ExpandedWrap disabled
                          // a philosopher that receives {eat} stops thinking and becomes hungry
                                  thinking = (
                                      on(atom("eat")) >> [=] {
                                          become(hungry);
                                          send(left, atom("take"), this);
                                          send(right, atom("take"), this);
                                      }
                                  );
                                  // wait for the first answer of a chopstick
                                  hungry = (
                                      on(atom("taken"), left) >> [=] {
                                          become(waiting_for(right));
                                      },
                                      on(atom("taken"), right) >> [=] {
                                          become(waiting_for(left));
                                      },
                                      on<atom("busy"), actor>() >> [=] {
                                          become(denied);
                                      }
                                  );
                                  // philosopher was not able to obtain the first chopstick
                                  denied = (
                                      on(atom("taken"), arg_match) >> [=](const actor& ptr) {
                                          send(ptr, atom("put"), this);
                                          send(this, atom("eat"));
                                          become(thinking);
                                      },
                                      on<atom("busy"), actor>() >> [=] {
                                          send(this, atom("eat"));
                                          become(thinking);
                                      }
                                  );
                                  // philosopher obtained both chopstick and eats (for five seconds)
                                  eating = (
                                      on(atom("think")) >> [=] {
                                          send(left, atom("put"), this);
                                          send(right, atom("put"), this);
                                          delayed_send(this, seconds(5), atom("eat"));
                                          aout(this) << name
                                                     << " puts down his chopsticks and starts to think\n";
                                          become(thinking);
                                      }
                                  );

                        Чёрт с ними с атомами - их легко можно заменить типами. Просто здесь видна группировка по состояниям с разными обработчиками одних и тех же сообщений.

                        Добавлено
                        Цитата Qraizer @
                        Ужас, да?

                        Ужас или нет, но... зачем?
                          Цитата MyNameIsIgor @
                          Цитата eao197 @
                          Потому, что в подавляющем большинстве случаев с сообщением связаны еще и какие-то данные. Т.о., при реальной работе вам кроме enum class msg с вариантами msg_1,...,msg_n предстоит вести дополнительные наборы структур или туплов.

                          Ну, а можно это буду решать я как пользователь?


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

                          Цитата MyNameIsIgor @
                          Цитата eao197 @
                          Ну вот и у нас аналогично. Всех особенностей реализации не спрячешь.

                          Сложностей, которые принёс бы отказ от QObject, несравнимо больше сложностей, которые появятся от отказа наследования для типа сообщения. Да я вообще никаких особых сложностей от произвольного типа не вижу. Да и у вас это уже было. А отказываться только из-за неудобства разработчиков... ну, библиотеки пишутся для удобства пользователей, а не создателей.

                          Значит это тот случай, где мы не смогли абстрагировать пользователя от деталей реализации.

                          Ну а по поводу "я не вижу", так пока не сделаешь сам и не попытаешься это разогнать, а потом посопровождать, много чего не видишь :(

                          Цитата MyNameIsIgor @
                          Цитата eao197 @
                          Мне не суть важно, насколько libcppa и SObjectizer конкурируют друг с другом. Намного важнее то, оставляют ли они C++ разработчиков в рамках C++ или же люди все-таки уходят в Erlang, Scala или еще куда-нибудь. Берут какую-нибудь Akka, а потом узкие места пытаются переписать на C или начинают бороться с GC. Тогда как можно было получить более качественный результат в C++.

                          А, простите, вы уже где-то показали, что ваш результат качественнее, кроме "я так считаю"? :)

                          Какой внезапный поворот заговора. Здесь, вообще-то, речь не шла о конкретно моем результате. Был наслышан о случаях, когда программы на Java имели проблемы и с производительностью, и с расходом памяти, и с надежностью, и с утечкой ресурсов, тогда как для похожих аналогов на C++ таких проблем не было.

                          Цитата MyNameIsIgor @
                          Цитата eao197 @
                          Про философов посмотрю. Нужно вкурить особенности тамошней реализации.

                          Ну, меня интересует не программа с точно такой же семантикой, а просто аналог конструкций
                          ExpandedWrap disabled
                            // a philosopher that receives {eat} stops thinking and becomes hungry
                                    thinking = (
                                        on(atom("eat")) >> [=] {
                                            become(hungry);
                                            send(left, atom("take"), this);
                                            send(right, atom("take"), this);
                                        }
                                    );
                                    // wait for the first answer of a chopstick
                                    hungry = (
                                        on(atom("taken"), left) >> [=] {
                                            become(waiting_for(right));
                                        },
                                        on(atom("taken"), right) >> [=] {
                                            become(waiting_for(left));
                                        },
                                        on<atom("busy"), actor>() >> [=] {
                                            become(denied);
                                        }
                                    );
                                    // philosopher was not able to obtain the first chopstick
                                    denied = (
                                        on(atom("taken"), arg_match) >> [=](const actor& ptr) {
                                            send(ptr, atom("put"), this);
                                            send(this, atom("eat"));
                                            become(thinking);
                                        },
                                        on<atom("busy"), actor>() >> [=] {
                                            send(this, atom("eat"));
                                            become(thinking);
                                        }
                                    );
                                    // philosopher obtained both chopstick and eats (for five seconds)
                                    eating = (
                                        on(atom("think")) >> [=] {
                                            send(left, atom("put"), this);
                                            send(right, atom("put"), this);
                                            delayed_send(this, seconds(5), atom("eat"));
                                            aout(this) << name
                                                       << " puts down his chopsticks and starts to think\n";
                                            become(thinking);
                                        }
                                    );

                          Чёрт с ними с атомами - их легко можно заменить типами. Просто здесь видна группировка по состояниям с разными обработчиками одних и тех же сообщений.

                          Я не совсем понимаю, что именно вы хотите увидеть. Если одни и те же сообщения по разному нужно обрабатывать в разных состояниях, то делается это так:
                          ExpandedWrap disabled
                            so_subscribe( mbox ).in( st_hungry ).event([](const taken&) {...} );
                            so_subscribe( mbox ).in( st_hungry ).event([](const busy&) {...} );
                            so_subscribe( mbox ).in( st_denied ).event([](const taken&) {...} );
                            so_subscribe( mbox ).in( st_denied ).event([](const busy&) {...} );
                            ...
                            Цитата eao197 @
                            Не можно, а нужно. Вы, как пользователь, сформируете свои критерии выбора конкретного инструмента

                            Хорошо, тогда я ставлю минус.
                            Цитата eao197 @
                            Ну а по поводу "я не вижу", так пока не сделаешь сам и не попытаешься это разогнать, а потом посопровождать, много чего не видишь

                            Так расскажите о сложностях отказа от наследования.
                            Цитата eao197 @
                            Какой внезапный поворот заговора. Здесь, вообще-то, речь не шла о конкретно моем результате

                            Почему же? Разговор о вашей библиотеке.
                            Цитата eao197 @
                            Если одни и те же сообщения по разному нужно обрабатывать в разных состояниях, то делается это так

                            Ясно, группировка с помощью форматирования кода :yes-sad:
                              Цитата MyNameIsIgor @
                              Цитата eao197 @
                              Не можно, а нужно. Вы, как пользователь, сформируете свои критерии выбора конкретного инструмента

                              Хорошо, тогда я ставлю минус.

                              Так об этом сразу было сказано: в плане сопоставления с образцом при разборе данных сообщения SObjectizer не идет ни в какое сравнение с libcppa.
                              Другое дело, что за все время работы с SObjectizer надобности в этом не было. Посему для вас минус, для меня это вообще не критерий.
                              Цитата MyNameIsIgor @
                              Цитата eao197 @
                              Ну а по поводу "я не вижу", так пока не сделаешь сам и не попытаешься это разогнать, а потом посопровождать, много чего не видишь

                              Так расскажите о сложностях отказа от наследования.

                              Может вы сначала попробуете описать преимущества этого?
                              Поскольку вот мы сначала работали без наследования. Из-за этого приходилось создавать дополнительные объекты со счетчиками ссылок. Не было возможностей просто так переадресовать тот же самый экземпляр сообщения в новый send или серию новых send-ов. И т.д. по мелочам. Отказались от всего этого, жизнь стала лучше :)
                              Цитата MyNameIsIgor @
                              Цитата eao197 @
                              Какой внезапный поворот заговора. Здесь, вообще-то, речь не шла о конкретно моем результате

                              Почему же? Разговор о вашей библиотеке.

                              Похоже, здесь опять какое-то недопонимание.
                              Попробую вот так объяснить. С начала 2000-х идет большой отток разработчиков из C++ в другие ниши (в основном в Java, частично в C#). В свое время это было оправдано, т.к. C++ развивался очень медленно. Да и память с гигагерцами никто не считал. Однако, время прошло, писать на C++ сейчас намного проще и безопаснее, а за счет некоторых возможностей языка (rvalue references, например) код получается еще быстрее и надежнее. Плюс на расход памяти и на мощность компьютеров вновь обращают внимание. Если лет 8-мь назад можно было встретить радостные упоминания, что RoR приложение отмасштабировано на 1000 серверов, то сейчас уже чаще заходит речь о другом: зачем платить за 1000 серверов с RoR приложением там, где можно обойтись 200 с Lift-приложением. Т.е. для возвращения достаточного интереса к использованию C++ вместо Java/C# сейчас больше условий, чем 10 лет назад. И, если этому поспособствуют библиотеки вроде libcppa, jss или SObjectizer, то это хорошо. Даже если 99% процентов C++ников будут пользоваться libcppa, а на долю jss и SO придется по 0.5%.

                              Что до SO, то на своей прошлой работе SO-проекты были самыми нагруженными, стабильными, протестированными и документированными. Некоторая доля заслуги в этом есть и SO, как простого и надежного инструмента.
                              Цитата MyNameIsIgor @
                              Цитата eao197 @
                              Если одни и те же сообщения по разному нужно обрабатывать в разных состояниях, то делается это так

                              Ясно, группировка с помощью форматирования кода :yes-sad:

                              Э... Это не принципиальное ограничение обусловленное какими-то архитектурными особенностями. Если кому-то потребуется, то можно будет сделать и такой вариант:
                              ExpandedWrap disabled
                                so_state( st_hungry ).mbox( mbox ).event( ... ).event( ... ).event( ... )...

                              Просто метод so_subscribe заточен под те кейсы, который были распространены у нас. Но он возвращает простенький прокси-объект, накапливающий информацию, а затем осуществляющий обращение к специальному методу агента для создания подписок. Аналогичным образом можно сделать и другой простенький прокси-объект, возвращаемый методом so_state().
                                Цитата MyNameIsIgor @
                                Цитата korvin @
                                Это всё наверное дико круто, но хотелось бы, чтоб оно выглядело менее адово.

                                Например. Но, я думаю, ты согласишься, что это всё не дотягивает до нормальных акторов без сопоставления с образцом.
                                IMHO, libcppa более вменяемая в этом плане. bsivko, что скажете о конкуренте?

                                Тут много чего уже сказали, но в общем с случае да, абстракции и инструменты работы над ними разные, и не все акторы/агенты одинаково полезны [в конкретных обстоятельствах].

                                Цитата MyNameIsIgor @
                                Цитата eao197 @
                                Не можно, а нужно. Вы, как пользователь, сформируете свои критерии выбора конкретного инструмента

                                Хорошо, тогда я ставлю минус.

                                MyNameIsIgor, какие вы используете (если используете) реализации модели акторов в боевых системах, в частности, на С++?

                                Цитата MyNameIsIgor @
                                В вашем примере нет ООП (или вы его не показали). Потому что для пользователя нет никакого профита от наследования - по вашим словам, это лишь артефакт реализации.

                                Пользователю прямого профита нет, но разработчик может при необходимости добавить что-то обобщающее. Как это сделано в QObject. И как бы это противоричиво с YAGNI не звучало.

                                А часть проблем разного типа под капотом SO могут решиться с помощью привязки к нативному или не очень smart_ptr/ptr. Также с помощью только него можно создавать акторы/агенты, выполняющие обобщенные действия (например принимать одиночные собщения, подождать, отправить пачку дальше). Но общий предок позволяет сделать ещё больше.
                                Сообщение отредактировано: bsivko -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (14) 1 2 [3] 4 5 ...  13 14 все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0914 ]   [ 18 queries used ]   [ Generated: 28.04.24, 11:34 GMT ]