Re[8]: SObjectizer: I Love This Game!
От: GU Glez  
Дата: 10.01.06 12:13
Оценка: 1 (1)
Здравствуйте, eao197, Вы писали:
E>Но тогда в GC-приложении должен быть свой SObjectizer.
0. Скорее всего.
E>Поэтому я и говорю, что если потребуется и будет заинтересованность, то сделаем
1. Заинтересованность будет однозначно. Хотя такой синтаксис в назвваниях и обозначениях немного отпугивает (некоторых уже не отпугивает после boost и stl , но для других — тяжеловато читать).

E>Мне просто интересно, захочет ли кто-то программировать в агентах, например, в C#, Python, Ruby или OCaml-е, или Lisp-е.

2. Нет... Пока нет. Не стоЯт еще такие задачи — есть более простые и "родные" способы для достижения подобных целей.

E>Второй вариант -- использовать для взаимодействия другие механизмы (SOAP, XML-RPC или CORBA).

Это правильно!

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

3. Еще бы и хелп небольшой написать. Тогда п.2, возможно отменяется.

E>Главная политическая проблема SObjectizer в том, что SObjectizer существует только на C++ и только для C++. В частности, возможности SObjectizer для создания распределенных приложений можно использовать исключительно в С++. Конечно, SObjectizer не мешает использовать в этом же приложении иные способы взаимодействия (CORBA, COM, SOAP, XML-RPC). Но и не помогает. А если в приложение встраивается ручная поддержка CORBA или SOAP, то встает вопрос: “К чему тогда вообще использовать SObjectizer?” И ответ на этот вопрос, особенно когда требуется интероперабельность с написанными на других языках приложениями, часто бывает не в пользу SObjectizer.

Выделенное и есть один из признаков отсутствия инфраструктуры.

E>Еще одна проблема наследуется SObjectizer от C++. В последнее время у C++ появились очень серьезные конкуренты. С одной стороны, это Java и .Net/C# с огромным количеством готовых библиотек и IDE нового поколения. Очень многих программистов от C++ отталкивает отсутствие настолько же удобных IDE (с автодополнением, автоподсказкой, поддержкой рефакторинга) как IDEA и Eclipse для Java, или VisualStudio+ReSharper для C#. В С++ с этим дела обстоят неважно. A у SObjectizer еще хуже — ведь сейчас нет ни одной IDE, способной поддерживать специфические особенности SObjectizer (хотя бы так, как VisualStudio помогла использовать MFC)...

E>[/q]
К сожалению и к счастью одновременно — это правда.
С уважением,
GU Glez [Джи Ю Глиз]
Re[9]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 10.01.06 12:21
Оценка:
Здравствуйте, GU Glez, Вы писали:

GG>1. Заинтересованность будет однозначно. Хотя такой синтаксис в назвваниях и обозначениях немного отпугивает (некоторых уже не отпугивает после boost и stl , но для других — тяжеловато читать).


Поживем -- увидим. А что касается нотации, так пока ни у кого проблем не было, быстро привыкают.

E>>Мне просто интересно, захочет ли кто-то программировать в агентах, например, в C#, Python, Ruby или OCaml-е, или Lisp-е.

GG>2. Нет... Пока нет. Не стоЯт еще такие задачи — есть более простые и "родные" способы для достижения подобных целей.

Можно ли раскрыть термин "подобных"? Или пример привести?

E>>Второй вариант -- использовать для взаимодействия другие механизмы (SOAP, XML-RPC или CORBA).

GG>Это правильно!


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


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[10]: SObjectizer: I Love This Game!
От: GU Glez  
Дата: 10.01.06 12:59
Оценка:
Здравствуйте, eao197, Вы писали:
GG>>[...].
E>Можно ли раскрыть термин "подобных"? Или пример привести?
Хм... пример... Я хотел сказать, что "Подобные" — означает нечто похожее по уровню. Сейчас так вот сразу сказать не могу — не так много я на C# в частности и на .NET вообще. Но суть одна — теперь на .NET можно, очень много сделать в программировании клиент-серверных (и не только) приложений без лишнего гемора (т.е. что думаю, то и пишу не заботясь о низкоуровневых деталях). И все это решается в контексте одной-двух парадигм — что многих и привлекает.

E>

E>Тогда, имхо, часть на SObjectizer усложняется. Появляются два вида взаимодействия -- асинхронное на уровне сообщений, когда границы между процессами размыты, и синхронное.
А это уже интересно. И вообще, чем это плохо или хорошо надо обдумавать и двигаться дальше. По мне так — если есть реальные проекты с GC, то вот на них и надо бы эксперемент проводить; если нет, то что-то стряпать более-менее все равно можно (GUI хотя бы), и вперед... если есть такая возможность, конечно.
С уважением,
GU Glez [Джи Ю Глиз]
Re[11]: SObjectizer: I Love This Game!
От: Dj.ValDen Украина http://ua.linkedin.com/in/dvalchuk
Дата: 10.01.06 19:24
Оценка:
Здравствуйте, AVC, Вы писали:

Спасибо за экскурс

>> Это могло бы помочь оценить возможности SObjectizer.


ничто так не поможет как возможность пощупать

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

Не скажу что жду уже сейчас Задача в которой бы, я думаю, этот фреймворк мне помог была полтора года назад... От Corba я тогда отказался — посчитал слишком тяжёлой и не нужной...

Время движется — может интерессные идеи появятся и этот фреймворк будет востребован... К тому времени думаю он ещё лучше будет
С уважением Denys Valchuk

IMHO чем больше мнений тем оптимальней выбор варианта... :)
Re[12]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 10.01.06 20:29
Оценка:
Здравствуйте, Dj.ValDen, Вы писали:

DV>ничто так не поможет как возможность пощупать




DV>Так что жду выхода в свет, с туториалом и более менее реалистичным тестовым проектом.


Т.е. имеющийся SObjectizer Book чем-то не достаточен?

И что бы хотелось видеть в качестве тестового проекта?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[13]: SObjectizer: I Love This Game!
От: Dj.ValDen Украина http://ua.linkedin.com/in/dvalchuk
Дата: 11.01.06 20:17
Оценка:
Здравствуйте, eao197, Вы писали:

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


DV>>ничто так не поможет как возможность пощупать


E>)


DV>>Так что жду выхода в свет, с туториалом и более менее реалистичным тестовым проектом.


E>Т.е. имеющийся SObjectizer Book чем-то не достаточен?


может я не правильно выразился
я имел ввиду удобный хелп
Book хорош
Но как книга, а как хелп — нет. Одно другое не исключает — так что книгу не удаляйте
Но удобный хелп, в виде chm, html или ещё чего очень помог бы...

Я ещё сторонник UML описания

E>И что бы хотелось видеть в качестве тестового проекта?


Естественно, что то наглядное и не требующее установки спец оборудования

Может даже и ваши примеры из книжки... Если честно я не люблю смотреть на код как на письмо
Вот письма я пишу чёрным по белому и ничего лишнего — а код предпочитаю с подсветкой синтаксиса
С уважением Denys Valchuk

IMHO чем больше мнений тем оптимальней выбор варианта... :)
Re[14]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 12.01.06 05:37
Оценка:
Здравствуйте, Dj.ValDen, Вы писали:

DV>я имел ввиду удобный хелп

DV>Но удобный хелп, в виде chm, html или ещё чего очень помог бы...
DV>Вот письма я пишу чёрным по белому и ничего лишнего — а код предпочитаю с подсветкой синтаксиса

Все это есть в виде html Reference, сгенерированного через doxygen. Как мне кажется, весьма подробный.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[14]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 12.01.06 10:38
Оценка: 2 (1)
Здравствуйте, Dj.ValDen, Вы писали:

DV>я имел ввиду удобный хелп


А вот так подойдет?
(оно же в zip-е (1.6Mb)).


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: SObjectizer: I Love This Game!
От: vdimas Россия  
Дата: 14.02.06 06:54
Оценка: 36 (1)
Здравствуйте, Евгений Охотников, Вы писали:

[примечание: часть переписки, опубликованная здесь по согласию сторон]

ЕО>Там я один вопрос как раз затрагиваю, о возможности портирования SObjectizer на какой-нибудь из managed языков. Поскольку у тебя, как я вижу, вполне лояльное отношение к C#, то интересно было бы узнать, заинтересовался ли бы ты лично SObjectizer-ом, будь он реализован на C#.



Мое мнение насчет реализации подобной наработки на C# примерно такое:
— очень интересный подход диспечеров, в принципе — это краеугольный камень
технологии.

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

Для дотнета, я уверен, была бы интересна богатая система диспечеризации
сообщений, а так же, разумеется, организация очередей сообщений к конкретным
объектам.

Из очевидных переделок под дотнет:
— события должны предоставляться делегатами, а не именами.
— сами сообщения лучше регистрировать по типу, а не по имени.
— другая терминология, события в дотнете — это "источник". Ваши send_msg
можно заменить/дополнить подписыванием вашего run-time на интересующие
события объектов.
— то, что вы называете событиями, в дотнете зовется обработчик оного — event
handler.
— возможным станет описывать в конфигурации, объекты какого типа создавать и
как их соединять друг с другом и с диспечером.

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

Ты поднимал вопросы асинхронности обработки сообщений и сетовал, что нет
возможности узнать результат обработки сообщения (или сам факт доставки). В
дотнете есть целый механизм вокруг IAsyncResult и динамического вызова
обработчиков. Далее. Необязательно синхронные вызовы делаются в том же
потоке!!! Можно вызвать событие другом потоке и дождаться завершения
обработки. С точки зрения объемлющего кода это будет выглядеть как
синхронное сообщение. На самом деле, конечно, все должно зависеть от
настроек. Т.е. некоторым событиям (методам) абсолютно все-равно в каком
потоке исполняться. В дотнете подобная доп. информация размечается
атрибутами. Так же можно атрибутами специфировать участие методов (событий)
в подписвании, вместо so_on_subscription().

В общем, если получиться гладко "вшить" диспетчеры в существующую
инфраструктуру .Net, то это все имеет смысл. Т.е. необходимо как-то
предусмотреть систему типов таким образом, чтобы практически одинаково
работать как с непосредственными прямым подключениями (синхронное
распространение событий), так и через диспетчера. Возможно, что
библиотека под дотнет совершенно неузнаваемо изменит первоначальное лицо и будет
прилично отличаться от оной на С++

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

Как я бы предложил попробовать переделать на дотнет: самому выступить в роли
предвзятого юзера-программиста библиотеки и написать несколько
высокоуровневых тестов (сценариев) именно так, как ты бы хотел все это
видеть синтаксически (т.е. максимально кратко и выразительно). Даже факт
компиллируемости необязателен. А я с удовольствием подсказывал бы, как тот
или иной момент выразить на C# в частности или в дотнет вообще.

Насчет — заинтересовался бы лично? Скорее да, если речь пойдет об
организации системы асинхронно взаимодействующих объектов.
Re[2]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 14.02.06 11:53
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Мое мнение насчет реализации подобной наработки на C# примерно такое:

V>- очень интересный подход диспечеров, в принципе — это краеугольный камень
V>технологии.

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

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

Следствием всего этого дела является, имхо, более простой способ создания многопоточных приложений. В чем-то похожий на подход Erlang-а. Но отличающийся от встроенных механизмов поддержки многопоточности в Ada или Java. Если диспетчеры обеспечивают для агента гарантию запуска его обработчиков только на контексте одной нити в один момент времени, то проблем взаимной синхронизации вообще нет. К этому привыкаешь и необходимость ручной работы с mutex-ами или condition variables начинает казаться слишком утомительной

V>Остальное — суть эмуляция вещей, которые сейчас в дотнет делают через

V>reflection или на делегатах. Даже разделение класса и агента похоже вызвано
V>необходимостью отделить декларативные конструкции от "обычных".

Не уверен, что точно понимаю о чем ты говоришь. Понятие агента (и соответственно специального класса agent_t) было выделено по очень простым причинам:
-- чтобы у агента можно было запрашивать специальную информацию (имя класса агента, например);
-- чтобы агентов можно было помещать в одну коллекцию в рамках кооперации агентов;
-- чтобы у агентов можно было вызывать специальные обработчики событий (so_on_subscription, so_on_deregistration).
В общем, в результате обычной декомпозиции ООП

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

Сами же обработчики событий должны быть обычными нестатическими методами. Как раз для манипуляции обработчиками событий вовсе не требовалось выделение отдельного класса agent_t.

V>Из очевидных переделок под дотнет:

V>- события должны предоставляться делегатами, а не именами.

Мне кажется, что имена как раз добавляют декларативности.

V>- сами сообщения лучше регистрировать по типу, а не по имени.


Здесь не все так просто. Один обработчик события может быть подписан на разные типы сообщений. А один тип (C++ класс/структура) может использоваться для реализации разных сообщений.

V>- другая терминология, события в дотнете — это "источник". Ваши send_msg

V>можно заменить/дополнить подписыванием вашего run-time на интересующие
V>события объектов.

Вот это не полностью понимаю. Возможно, из-за слишком поверхностного знания дотнета.

V>- то, что вы называете событиями, в дотнете зовется обработчик оного — event

V>handler.

Термин event handler у нас так же есть
Просто у нас нет события без обработчика и обработчика события без события Поэтому для краткости проще называть и события, и обработчики просто событиями.

V>- возможным станет описывать в конфигурации, объекты какого типа создавать и

V>как их соединять друг с другом и с диспечером.

Да это, в принципе, и в C++ возможно. Просто во время выпуска первой версии SObjectizer не было времени докрутить эту идею до реализации.

V>Да, кстати, а есть ли в твоей схеме возможность непосредственной стыковки?

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

Нет, такого нет и я думаю, что это уже будет не столько SObjectizer. Скорее тебе нужно что-то в стиле libsigc++.

V>Необязательно синхронные вызовы делаются в том же

V>потоке!!! Можно вызвать событие другом потоке и дождаться завершения
V>обработки. С точки зрения объемлющего кода это будет выглядеть как
V>синхронное сообщение. На самом деле, конечно, все должно зависеть от
V>настроек. Т.е. некоторым событиям (методам) абсолютно все-равно в каком
V>потоке исполняться. В дотнете подобная доп. информация размечается
V>атрибутами. Так же можно атрибутами специфировать участие методов (событий)
V>в подписвании, вместо so_on_subscription().

С синхронностью все не так просто
Если синхронный вызов делается из нити, не относящейся к диспетчерам SObjectizer, то особых проблем нет. Но если синхронный вызов идет из обработчика событий агента, то в результате можно получить тупик, если в конце-концов потребуется задействовать нить диспетчера, на которой был инициирован синхронный вызов. Контроль и диагностирование таких тупиков может быть слишком дорогой операцией (при том, что потенциально она будет слишком редкой).

V>В общем, если получиться гладко "вшить" диспетчеры в существующую

V>инфраструктуру .Net, то это все имеет смысл. Т.е. необходимо как-то
V>предусмотреть систему типов таким образом, чтобы практически одинаково
V>работать как с непосредственными прямым подключениями (синхронное
V>распространение событий), так и через диспетчера. Возможно, что
V>библиотека под дотнет совершенно неузнаваемо изменит первоначальное лицо и будет
V>прилично отличаться от оной на С++

Очень на то похоже

V>Но это не страшно, если останется суть. А суть, насколько я понял, в

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

Очень возможно. Особенно с учетом автоматической сборки мусора в дотнете. Собственно, в этом и привлекательность потрирования SObjectizer в managed среды, что многие вещи там уже готовы или проще. Смущает возможная производительность, т.к. вызов обработчика события -- это весьма существенный оверхед. Хотя, судя по общему мнению, JIT собирается творить чудеса

Тут важно другое оценить -- заинтересованы ли пользователи managed языков в подобных инструментов. Насколько я могу судить, многие разработки на Java ведутся в рамках Web-технологий и по разным существующим спецификациям (J2EE со товарищи), на готовых фреймворках и серверах приложений. Поэтому я не очень понимаю, заинтересуется ли кто-нибудь из Java разработчиков чем-то подобным SObjectizer-у. У C#, имхо, список возможных предметных областей гораздо шире, а список готовых инструментов -- наоборот.

V>Насчет — заинтересовался бы лично? Скорее да, если речь пойдет об

V>организации системы асинхронно взаимодействующих объектов.

Спасибо за столь развернутое мнение.


Еще вопрос: а как бы ты оценил саму статью? Стиль, форму подачи материала, его объем?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: SObjectizer: I Love This Game!
От: mrozov  
Дата: 14.02.06 12:53
Оценка: 24 (1) +2 :))
Здравствуйте, Аноним, Вы писали:

А>Ребята не имею ничего личного к автору,

Я имею — в хорошем смысле.
А>при общении с ним убеждался в его проффесионализме,
Аналогично.
А> Софт, написанный на этом движке, (работал с ним лично)
Аналогично.
А>это один единый гармонично работающий глюк. Не поддающийся логичному лечению
У меня работает, как часы. Ни одного глюка за несколько лет не замечено. Может, дело-таки не совсем в Евгении?
Re: SObjectizer: I Love This Game!
От: mrozov  
Дата: 16.02.06 13:01
Оценка: 24 (1)
Здравствуйте, Евгений Охотников, Вы писали:

Привет!

Сразу — концепция управления потоками мне очень понравилась.
Концепция управления состояниями очень не понравилось.
С последнего и начну.

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

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

Также хотелось бы заметить, что есть и другие варианты решения подобной задачи. Например — com+ events. Там есть две модели обработки — синхронная (гут) и асинхронная на основе MQ (даже лучше).
Соответственно, в идеальной системе такого рода эти модели было бы неплохо предусмотреть. Опять же, хорошо бы иметь возможность отследить судьбу асинхронной обработки.

На сим пока закончу, ибо выдохся.

Только один поинт — приплетать сюда events из .net я бы не стал. Не нужны они тут.
Re[3]: SObjectizer: I Love This Game!
От: vdimas Россия  
Дата: 16.02.06 20:26
Оценка: 11 (1)
Здравствуйте, eao197, Вы писали:

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


Нет, все же программистом
Просто программист использует "другой" инструмент. Знаешь, насчет той статьи, я бы добавил туда более четкого позиционирования технологии (может быть в ущерб подробностям реализации). Т.е., прежде, чем что-то обсуждать, было бы неплохо понять — что именно мы собираемся обсуждать. SObjectizer — это инструмент. Инструмент для чего? Вон ниже mrozov вообще выдвигает свои соображения насчет распределенной жизни объектов и их состояний. Только мне его рассуждения показались очень уж частными, т.е. опять же — моментами, с которыми сталкивался он лично, но которые не обязательно хорошо подходят для других задач.

E>Второй краеугольный камень -- это взаимодействие на основе сообщений. Может быть даже он главнее.


Женя, я делаю акцент на том, что рассматривал твой вопрос с т.з. реализации SObjectizer на дотнет. А в нем взаимодействие на основе сообщений УЖЕ реализовано. Т.е. мы можем вызывать методы асинхронно (просто посылать сообщение), синхронно (послать сообщение и дожаться ответа), и откликаться на события, на которые подписаны (на одно событие может быть подписано куча подписчиков). Событие — это обратный вызов (call back), т.е. все то, что делает твоя система. Однако, при этом подробности потоков исполнения, блокировки и пр. реализованы лишь в 2-х моделях: STA и MTA. Твои диспеччеры позволяют создавать произвольное количество "групп" — аппартаментов, и позволяют создавать диспеччеры, которые этими аппартаментами управляют. Вот на какой именно уровень ты залез. И мне это кажется весьма любопытным. Более того, есть еще один момент. В дотнет нужно явно указывать — синхронно или асинхронно я вызываю события. Мне бы хотелось... вынести это из вызывающего кода, что-ли.

Далее. Ты все время говоришь об взаимодействии на основе сообщений. Вообще-то считается, что вызов метода объекта — это и есть посылка ему некоего сообщения. (Обратный вызов, т.е. событие для подписчика, разумеется тоже). Просто в твоей системе все делается через обратный край воронки: SendMsg(), а в дотнете эта воронка двухсторонняя: с обоих сторон обычные вызовы обычных методов, а между ними — транспорт с пакетами сообщений, STA и MTA диспетчеры.

Согласись, что SendMsg("ClosePipe", param) проигрывает этому: ClosePipe(param) сразу по многим пунктам.

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


E>Во-первых, поэтому возможно само существование диспетчера. Во-вторых, появляется возможность делать относительно прозрачную распределенность.


Да, для С++ так и есть. На отсутствие НОРМАЛЬНЫХ сетевых высокоуровневых библиотек для С++ Страуструп жаловался более 10 лет назад, но воз и ныне там, к большому сожалению. Для дотнета распределенность достигается весьма прозрачно. Слово прозрачно — ключевое. Для алгоритма не имеет значения, с локальным объектом идет работа, или с его удаленным прокси. Правда есть одна оговорка — это прозрачно до тех пор, пока имеющиеся возможности устраивают. Как только чего-то нехватает в дотнет, то приходится довольно много делать "ручками", даже в нем. (Собственно, как и везде — неудивительно).

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

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


Смотри, как сделать простейшую распределенную систему на дотнете, которая очень близко копирует именно твою архитектуру:

// это сигнатура сообщения
public delegate void CurrencyChangedMsg(object sender, string currencyCode, double currency);

// это наш главный диспетчер
public interface ICurrencyMarket {
    event CurrencyChangedMsg CurrencyChanged;
}


Затем, интересующие агенты получают каким-либо образом ссылку на экземпляр CurrencyMarket, и подписываются на сообщения, например так:
public class AirportTabloid : Form {

blah blah blah 

    void ConnectToCurrencyMarkets() {
        // подписываемся на события от 3-х разных диспетчеров во всем мире.
        ICurrencyMarket market = (ICurrencyMarket)RemotingServices
            .Connect("tcp://currency.market.com:8085/Dispatcher", typeof(ICurrencyMarket))
        market.CurrencyChanged += OnCurrencyChanged;

        market = (ICurrencyMarket)RemotingServices
            .Connect("http://www.currency.jp/currency", typeof(ICurrencyMarket))
        market.CurrencyChanged += OnCurrencyChanged;

        market = (ICurrencyMarket)RemotingServices
            .Connect("iiop://privatbank.ru:11500/Dispatcher", typeof(ICurrencyMarket))
        market.CurrencyChanged += OnCurrencyChanged;
    }

    void OnCurrencyChanged(object sender, string currencyCode, double currency) {
        TextBox tb = FindByCurrencyCode(currencyCode);
        if(tb!=null)
            tb.Text = currency.Format("C");
    }

}


(обрати внимание на разные заголовки URL )

Видишь, в чем основное отличие от твоей имплементации на С++? В том, что программист орудует НЕПОСРЕДСТВЕННО прикладными абстракциями, а не их строковыми идентификаторами.


E>Следствием всего этого дела является, имхо, более простой способ создания многопоточных приложений. В чем-то похожий на подход Erlang-а. Но отличающийся от встроенных механизмов поддержки многопоточности в Ada или Java. Если диспетчеры обеспечивают для агента гарантию запуска его обработчиков только на контексте одной нити в один момент времени, то проблем взаимной синхронизации вообще нет. К этому привыкаешь и необходимость ручной работы с mutex-ами или condition variables начинает казаться слишком утомительной


Да-да, это нам было знакомо еще с COM, действительно, порой очень удобно. Но, к сожалению, у программистов не было возможности явно управлять всеми этими механизмами. Ведь мне может захотеться одну группу методов исполнять в одном треде, а другую — в другом. Т.е. часто бывает так, что синхронизировать мютексами надо не весь объект, а его отдельные прикладные аспекты (абстракции). В общем, было бы интересно даже просто поучаствовать в обсуждении этого дела.

V>>Остальное — суть эмуляция вещей, которые сейчас в дотнет делают через

V>>reflection или на делегатах. Даже разделение класса и агента похоже вызвано
V>>необходимостью отделить декларативные конструкции от "обычных".

E>Не уверен, что точно понимаю о чем ты говоришь. Понятие агента (и соответственно специального класса agent_t) было выделено по очень простым причинам:

E>-- чтобы у агента можно было запрашивать специальную информацию (имя класса агента, например);
E>-- чтобы агентов можно было помещать в одну коллекцию в рамках кооперации агентов;
E>-- чтобы у агентов можно было вызывать специальные обработчики событий (so_on_subscription, so_on_deregistration).
E>В общем, в результате обычной декомпозиции ООП

В дотнет есть TransparentProxy и СontextBoundObject. Это я даю наименования классов, которые относятся к данной теме и функциональность которых может показаться тебе очччень любопытной.


V>>Из очевидных переделок под дотнет:

V>>- события должны предоставляться делегатами, а не именами.

E>Мне кажется, что имена как раз добавляют декларативности.


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


E>Здесь не все так просто. Один обработчик события может быть подписан на разные типы сообщений. А один тип (C++ класс/структура) может использоваться для реализации разных сообщений.


В общем, посмотри на пример. В дотнет ты можешь подписаться на событие, если сигнатура твоего метода совпадает с сигнатурой события. Т.е. ты можешь подписать на один и тот же метод-обработчик события от РАЗНЫХ источников совершенно разного типа (в примере указан один тип для 3-х удаленных серверов, но это могли бы быть совершенно разные 3 типа), которые могут плеваться совершенно разными типами сообщений. Главное — чтобы совпадали сигнатуры.


V>>- другая терминология, события в дотнете — это "источник". Ваши send_msg

V>>можно заменить/дополнить подписыванием вашего run-time на интересующие
V>>события объектов.

E>Вот это не полностью понимаю. Возможно, из-за слишком поверхностного знания дотнета.


Я в примере показал как это выглядит внешне. Ну а как оно выглядит внутренне — это надо знакомится с System.Runtime.Remoting в mscorlib, лучше всего рефлектором + MSDN.


E>Просто у нас нет события без обработчика и обработчика события без события Поэтому для краткости проще называть и события, и обработчики просто событиями.


Хм... а разве не может быть так, что в какой-то момент на какое-то событие нет заинтересованных обработчиков (агентов)? Вполне нормальная ситуация...

V>>- возможным станет описывать в конфигурации, объекты какого типа создавать и

V>>как их соединять друг с другом и с диспечером.

E>Да это, в принципе, и в C++ возможно. Просто во время выпуска первой версии SObjectizer не было времени докрутить эту идею до реализации.


В дотнет это будет просто как никогда. В моем примере мне бы хотелось вместо хардкодного тела метода ConnectToCurrencyMarkets() описать все это в стандартном файле конфигурации... Неплохо так же иметь к нему визуальный редактор

V>>Да, кстати, а есть ли в твоей схеме возможность непосредственной стыковки?

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

E>Нет, такого нет и я думаю, что это уже будет не столько SObjectizer. Скорее тебе нужно что-то в стиле libsigc++.


И да и нет... Я ведь не зря говорил про "гладкую" стыковку с механизмом дотнета. В общем, оба способа должны внешне выглядеть одинаково. И не важно как это будет называться, SObjectizer или boost::signal. Какой конкретно механизм используется для каждого конкретного соединения диспетчера и агента должно зависеть только лишь от их взаимного расположения и суммарных взаимных политик и настроек.


E>С синхронностью все не так просто

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

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

E>Тут важно другое оценить -- заинтересованы ли пользователи managed языков в подобных инструментов. Насколько я могу судить, многие разработки на Java ведутся в рамках Web-технологий и по разным существующим спецификациям (J2EE со товарищи), на готовых фреймворках и серверах приложений. Поэтому я не очень понимаю, заинтересуется ли кто-нибудь из Java разработчиков чем-то подобным SObjectizer-у. У C#, имхо, список возможных предметных областей гораздо шире, а список готовых инструментов -- наоборот.


Далеко не всем будет интересно, но заинтересованные найдутся, разумеется. Пока что люди заинтересованы не столько тактико-техническими характеристиками своих систем, сколько самим фактом реализации таких систем. А для этого и встроенных возможностей дотнета вполне хватает. А вот когда захочется делать эффективно, но по прежнему просто — потребуютс тулзы, типа обсуждаемого.
Re[4]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 17.02.06 12:28
Оценка:
Здравствуйте, vdimas

Дима, интересный ответ получился, нужно его покурить... Пока же несколько простых уточнений.

E>>Здесь не все так просто. Один обработчик события может быть подписан на разные типы сообщений. А один тип (C++ класс/структура) может использоваться для реализации разных сообщений.


V>В общем, посмотри на пример. В дотнет ты можешь подписаться на событие, если сигнатура твоего метода совпадает с сигнатурой события. Т.е. ты можешь подписать на один и тот же метод-обработчик события от РАЗНЫХ источников совершенно разного типа (в примере указан один тип для 3-х удаленных серверов, но это могли бы быть совершенно разные 3 типа), которые могут плеваться совершенно разными типами сообщений. Главное — чтобы совпадали сигнатуры.


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

И еще один момент -- сообщения, в отличии от сигнатур методов, проще расширять.

E>>Просто у нас нет события без обработчика и обработчика события без события Поэтому для краткости проще называть и события, и обработчики просто событиями.


V>Хм... а разве не может быть так, что в какой-то момент на какое-то событие нет заинтересованных обработчиков (агентов)? Вполне нормальная ситуация...


Так в том-то и дело, что событие -- это факт реакции конкретного агента на конкретное сообщение. Если агент не заинтересован в сообщении или агента просто нет, то нет и события, а сообщения уходят либо в пустоту, либо другим агентам.

E>>Нет, такого нет и я думаю, что это уже будет не столько SObjectizer. Скорее тебе нужно что-то в стиле libsigc++.


V>И да и нет... Я ведь не зря говорил про "гладкую" стыковку с механизмом дотнета. В общем, оба способа должны внешне выглядеть одинаково. И не важно как это будет называться, SObjectizer или boost::signal. Какой конкретно механизм используется для каждого конкретного соединения диспетчера и агента должно зависеть только лишь от их взаимного расположения и суммарных взаимных политик и настроек.


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


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: SObjectizer: I Love This Game!
От: vdimas Россия  
Дата: 17.02.06 13:29
Оценка: 10 (1)
Здравствуйте, eao197, Вы писали:

V>>В общем, посмотри на пример. В дотнет ты можешь подписаться на событие, если сигнатура твоего метода совпадает с сигнатурой события. Т.е. ты можешь подписать на один и тот же метод-обработчик события от РАЗНЫХ источников совершенно разного типа (в примере указан один тип для 3-х удаленных серверов, но это могли бы быть совершенно разные 3 типа), которые могут плеваться совершенно разными типами сообщений. Главное — чтобы совпадали сигнатуры.


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


Да, в моей терминологии это было бы — несколько "входных точек", то бишь, несколько методов, по одному на каждую сигнатуру. Знаешь, как подобное разруливается в Windows.Forms? Там используется одна сигнатура на большинство событий, вот она:
public delegate void EventHandler(object sender, EventArgs e);


Итак, sender — кто угодно, EventArgs — абсолютно пустой класс, просто корень базовой иерархии для других аргументов событий. Понятное дело, что через эту схему можно прогнать произвольное кол-во типов сообщений, совместимых с одной и той же сигнатурой "точки входа", то бишь метода-обработчика (event handler).

Но мне подобные схемы не нравятся так же, как использование void* в С++. Пусть MS выбрала именно такую сигнатуру по уважительной причине (тонны типов конролов и тонны сообщений), свое ПО я предпочитаю выражать во вполне конкретных типах и напрягать компилятор на первоначальную проверку логики программы, то бишь использовать типизацию.

E>И еще один момент -- сообщения, в отличии от сигнатур методов, проще расширять.


Ок, как насчет еще большей модификации приведенной схемы:
public class MsgBase {}

public delegate void MsgHandler(MsgBase msg); // вот такая сигнатура


Но мне такая схема совершенно не нравится. Ведь все-равно внутри обработчика придется делать некий swtch-case (if-else) по типу сообщения и обрабатывать каждый тип по-своему. Так почему бы не выполнить явную функциональную декомпозицию и не подписать разные сообщения сразу на "нужные" точки входа?

Ну и опять же — типизированность. В моем подходе ты принципиально не сможешь подписаться на сообщение, которое не умеешь обрабатывать.

Да, важный момент. Насколько я понял, в твоих реальных системах ты часто использовал только лишь имя (идентификатор) сообщения. Да, это важный класс сообщений, которые интересны самим только фактом своего возникновения.
public delegate void Notify();

public IMyServer {
    event Notify Event1, Event2, Event3 ... EventN;
}

public MyClient {

    void Connect(IMyServer server) {
        server.Event1+=OnEvent1To3;
        server.Event2+=OnEvent1To3;
        server.Event3+=OnEvent1To3;

        server.Event4+=OnEvent4ToN;
        ...
        server.EventN+=OnEvent4ToN;
    }

    // здесь мы обрабатываем одну группу сообщений
    void OnEvent1To3() { ... }

    // здесь - другую
    void OnEvent4ToN() { ... }
}


Итак, у нас есть одна сигнатура — пустая, и куча событий (терминология дотнет), использующих эту сигнатуру. И есть 2 обработчика событий, OnEvent1To3 мы подписали первые 3 события, на OnEvent4ToN — остальные.

Согласись, довольно-таки гибко и главное, подобный код — самодокументируем по сути, его легко понять. Я уверен, что ты все понял.

E>>>Просто у нас нет события без обработчика и обработчика события без события Поэтому для краткости проще называть и события, и обработчики просто событиями.


V>>Хм... а разве не может быть так, что в какой-то момент на какое-то событие нет заинтересованных обработчиков (агентов)? Вполне нормальная ситуация...


E>Так в том-то и дело, что событие -- это факт реакции конкретного агента на конкретное сообщение. Если агент не заинтересован в сообщении или агента просто нет, то нет и события, а сообщения уходят либо в пустоту, либо другим агентам.


Понятно, опять расхождение в терминологии. Я тебя понял, я примерно это и имел в виду.


V>>И да и нет... Я ведь не зря говорил про "гладкую" стыковку с механизмом дотнета. В общем, оба способа должны внешне выглядеть одинаково. И не важно как это будет называться, SObjectizer или boost::signal. Какой конкретно механизм используется для каждого конкретного соединения диспетчера и агента должно зависеть только лишь от их взаимного расположения и суммарных взаимных политик и настроек.


E>Дело в том, что сейчас в SObjectizer есть механизм т.н. insend-событий -- это когда SObjectizer вызывает обработчик события прямо внутри send_msg и на контексте той же нити. Тот, кто вызывает send_msg даже не знает, что insend-события уже отработали. Для отправителя сообщения внешне ничего не изменилось.


Ну, замечательно... Для GUI этот способ весьма востребован.
Re: SObjectizer: I Love This Game!
От: VVB16 Россия  
Дата: 17.02.06 13:53
Оценка:
Здравствуйте, Евгений Охотников, Вы писали:

Жаль что при создании SObjectizer вы сразу не стали использовать ACE.
Там как раз ActiveObjects есть и механизмы для организации их работы.
Re[6]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 17.02.06 14:36
Оценка:
Здравствуйте, vdimas, Вы писали:

E>>И еще один момент -- сообщения, в отличии от сигнатур методов, проще расширять.


V>Ок, как насчет еще большей модификации приведенной схемы:

V>
V>public class MsgBase {}

V>public delegate void MsgHandler(MsgBase msg); // вот такая сигнатура
V>


Как только появляется сигнатура с одним параметром msg, то сразу напоминает SObjectizer.

V>Но мне такая схема совершенно не нравится. Ведь все-равно внутри обработчика придется делать некий swtch-case (if-else) по типу сообщения и обрабатывать каждый тип по-своему. Так почему бы не выполнить явную функциональную декомпозицию и не подписать разные сообщения сразу на "нужные" точки входа?


V>Ну и опять же — типизированность. В моем подходе ты принципиально не сможешь подписаться на сообщение, которое не умеешь обрабатывать.


В SObjectizer от этого так же можно защититься, для этого специальный способ описания события существует. И используется.

Да я понимаю о чем ты говоришь. Это на самом деле так (опять вспоминаются вечные споры динамическая типизация+duck typing против статической типизации).

Хотя в данном конкретном случае я говорил о добавлении в MsgBase новых полей, а не новых наследников. По аналогии с протоколами -- новая версия протокола остается совместимой с предыдущей версией, но добавляет новые поля, которые старая версия может проигнорировать. Подобное расширение, перенесенное на методы будет означать, что каждое новое расширение нужно будет добавлять новый метод-отправитель сообщения:
ClosePipe(pipeId);
ClosePipe(pipeId, flushMode);
ClosePipe(pipeId, flushMode, flushTimeout);
ClosePipe(pipeId, reopenTimeout);
ClosePipe(pipeId, flushMode, flushTimeout, reopenTimeout);

Такие вещи в динамических языках удобнее выглядят, там параметры местами менять можно:
close_pipe pipe_id
close_pipe pipe_id, :flush_mode => mode
close_pipe pipe_id, :flush_timeout => tv, :flush_mode => mode
close_pipe pipe_id, :reopen_timeout => tv
close_pipe pipe_id, :flush_mode => mode, reopen_timeout => tv_reopen, :flush_mode => tv_flush


По поводу типизации я думал вот чего сделать в свое время, чтобы отсылка была не через send_msg напрямую, а чтобы в каждое сообщение отсылалось с помощью статического метода в типе сообщения:
msg_close_pipe::send( pipe_id, flush_mode, flush_timeout );
msg_close_pipe::send( pipe_id, flush_mode, flush_timeout, reopen_timeout );

а все обращения к send_msg скрывались бы внутри send().

Но здесь и трудоемкость большая (для C++) и сложно один тип использовать для нескольких сообщений с разными именами типов. Главная причина отсутствия, все же, в трудоемкости. Но я надеюсь, что когда для агентов в C++ начнет применяться кодогенерация, такая штука в SObjectizer появится.

V>Согласись, довольно-таки гибко и главное, подобный код — самодокументируем по сути, его легко понять. Я уверен, что ты все понял.


Угу, понял. Вот так это могло бы выглядеть в SObjectizer на C++.
so_4::rt::evt_subscr_t from1to3;
from1to3.add( "server", "event_1" );
from1to3.add( "server", "event_2" );
from1to3.add( "server", "event_3" );
so_4::api::subscribe_event( "a_my", "evt_1to3", from1to3,  so_4::rt::evt_subscr_t::e_change_all );

so_4::rt::evt_subscr_t from4toN;
from4toN.add( "server", "event_4" );
from4toN.add( "server", "event_4" );
so_4::api::subscribe_event( "a_my", "evt_4toN", from4toN, so_4::rt::evt_subscr_t::e_change_all );


Дима, у меня предложение: пока тему статической vs динамической типизации не развивать.
Я понял твою точку зрения. Но есть и еще такой фактор, что используемый сейчас в SObjectizer подход позволяет добавить в статически типизированный C++ какие-то черты динамической типизации. Иногда полезно. Хотя во мне может еще отставаться остаточное впечатление (стереотип) с тех времен, когда у предшественника SObjectizer-а был визуальный дизайнер, а все конструирование осуществлялось как прописывание имен в соответствующих формочках.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 17.02.06 14:45
Оценка:
Здравствуйте, VVB16, Вы писали:

VVB>Жаль что при создании SObjectizer вы сразу не стали использовать ACE.


Сейчас разрабатывается обновленная версия SObjectizer, в которой ACE как раз используется в качестве нижнего уровня.

VVB>Там как раз ActiveObjects есть и механизмы для организации их работы.


Дело в том, что ACE и SObjectizer предоставляют разные подходы к организации работы активных объектов. Подход ACE, имхо, ориентирован в первую очередь на обработку потоков данных из коммуникационых каналов. И все преимущества подхода ACE начинают сказываться, когда применяются высоуровневые фреймворки ACE, т.к. Task и Streams.

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

Так же, ACE предлагает очень низкоуровневые средства для организации распределенных приложений. Нужно будет самостоятельно программировать весь data flow и преобразование данных. SObjectizer здесь так же серьезно упрощает работу программисту.

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


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: SObjectizer: I Love This Game!
От: vim  
Дата: 18.02.06 10:35
Оценка: 13 (1)
Мне понравилась статья в RSDN о SObjectizer и собственно сама
платформа. Хотелось бы узнать можно получить SObjectizer для
разработки не комерческих продуктов в качестве одного из компанентов,
к примеру учебно-исследовательские работы, диплом.
Re[2]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 18.02.06 13:11
Оценка:
Здравствуйте, vim, Вы писали:

vim>Мне понравилась статья в RSDN о SObjectizer и собственно сама

vim>платформа. Хотелось бы узнать можно получить SObjectizer для
vim>разработки не комерческих продуктов в качестве одного из компанентов,
vim>к примеру учебно-исследовательские работы, диплом.

Приятно слышать такие слова. Спасибо за отзыв.

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


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