Re[25]: Функциональные типы (параллельная ветка)
От: gbear Россия  
Дата: 30.06.05 05:55
Оценка:
Здравствуйте, eao197, Вы писали:

Далее... Чиатл это — много думал...

Сдается мне, что проблема притянута за уши... По крайней мере, в рамках .NET. Такие "проблемы" на раз два решаются дизайном. В примере с сервисом отсылки SMS нужно исходить из следующих положений:

1. Клиент про реализацию сервера не должен знать как можно меньше. В пределе, только публичный интерфейс.
2. Расширение фунциональности сервера — всегда — должно вестись не за счет расширения какого либо публичного интерфейса, но за счет расширения набора этих интерфейсов.

И будет вам счастье. Проблема, наверное, опят же в том, что, в той среде откуда ростут ноги у subclassing by extension нет понятия аналогичного pure interface assembly. Если бы было, то решение выглядело бы, например так:

Есть pure interface assembly SimpleSMSService с интерфейсом ISimpleSMSService с методом

void SendSMS(Destination dest,Destination src, SMSEncoding encoding,string msg);


Есть сервис который реализует этот интерфейс. Например через класс

class SMSService : ISimpleSMSService


"Общение" клиента с сервером идёт исходя, например, из того, что:
1. Сервер общеизвестный тип. (На самом деле, совсем не обязательно).
2. Клиент работает с сервером приводя тип сервера к типу известного ему интерфейса, в данном случае к ISimpleSMSService.

Далее... В какой-то момент нам потребывалось расширить функциональность сервера например таким образом:

void SendSMS(Destination[] dest,Destination src, SMSEncoding encoding,string msg);


В этом случае заводим новый интерфейс (естественно в другой сборке), например, ISimpleSMSServiceExt c этим методом... Класс сервиса в этом случае расширяется через:

class SMSService : ISimpleSMSService, ISimpleSMSServiceExt


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

Или, опять "фишку не просёк"?

---
С уважением, Сиваков Константин.
Re[27]: Функциональные типы (параллельная ветка)
От: gbear Россия  
Дата: 30.06.05 06:25
Оценка: +1
Здравствуйте, eao197, Вы писали:

G>> Просто, имхо, тот же пример с pdu_t прекрасно "ложиться" на шаблон Visitor — и никакие указатели и делегаты тут, собственно, не нужны. Если уж приспичило через делегаты, то тут надо подходить с точки зрения ФП...


E>Да, можно через Visitor. А можно и без. В C++ есть свобода выбора, что хорошо.


Уважаемый... Пример с pdu_t, если я не ошибаюсь, приведён Вами на просьбу привести пример где это (работа с "голыми" указателями) нужно. А по всему выходит что это пример того где Вы это используете.

Есть разница...

G>> Т.е. например, в session_t.process_outgoing передавать делегат с конкретной ф-цей проверки конкретного экземпляра наследника pdu_t... Да и сам pdu_t в этом случае, собственно не нужен.


E>process_outgoing может инициировать много разных действий. И все что ему нужно для работы -- это объект pdu_t. Грузить метод process_outgoing дополнительными параметрами в виде делегатов для проверки -- это уже маразмом попахивает. Уж лучше в методе established() создавать и сохранять объект visitor.


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

---
С уважением, Сиваков Константин.
Re[26]: Функциональные типы (параллельная ветка)
От: vdimas Россия  
Дата: 30.06.05 06:37
Оценка:
Здравствуйте, IT, Вы писали:

V>>Более того, понятие function object несомненно более широкое понятие, чем Delegate. Делегат — лишь частный случай, осуществляющий делегирование вызовов третьей стороне. А оно не всегда нужно, вот в чем дело-то (хотя, очень удобно для GUI).


V>>Новоявленные анонимные делегаты как раз пытаются решить проблему избавления от "третей стороны",


IT>Насколько мне известно, анонимные делегаты — это просто синтаксический сахарок. Никаких новых концепций в язык они не привносят.


С т.з. юзера языка — это непосредственное описание логики callback-функции. Юзер избавляется от необходимости выделять/описывать/именовать/обслуживать отдельную третью сущность, так необходимую для работы концепции callback, реализованной на делегатах.

--------
Я вот только не догоняю одной вещи. В делегате есть метод Invoke() с такой же сигнатурой, как в объявлении типа делегата. Почему бы было не упрятать анонимный код в эту ф-ию? Зачем генерить еще одну лишнюю сущность и понижать эффективность двойным коссвенным вызовом?
Re[28]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 30.06.05 06:39
Оценка:
Здравствуйте, gbear, Вы писали:

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


G>>>

G>>>клиент отсылает запросы на сервер и каждый запрос должен уникальным образом однозначно идентифицироваться


G>>>Кем, идентифицироваться? Если клиентом — то для этого ему совсем не обязательно, посылать некий id серверу. Или не согласны? Даже в случае асинхронного взаимодействия — совсем, необязательно.


E>>Если каждый запрос идет через свой канал (как http-запросы), то не нужен, в принципе. Хотя лучще все же идентификаторы со стороны клиента на сторону сервера передавать, если обработка запроса может занять длительное время.

E>>А если все идет через один канал, да еще в асинхронном режиме, то идентификатор еще как нужен.

G>В смысле, один end-point? Но, даже в этом случае соглашусь только в случае, если порядок доставки сообщений неопределён.


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

G>>> В случаее, если знать тип id маршрутизатору не пологается... а пологается знать только базовый тип, то и работать он с ним смогЕт только как с базовым... Причем виртуальность в этом случае строго противопоказана... на стороне маршрутизатора нет кода типа id. Правильно?


E>>А кто сказал, что нет. Есть Как и информация о том, что этот тип производен от базового типа.


G>Э-э-э... А в чем тогда, собственно, проблема-то? Спрашиваю, потому как здесь
Автор: eao197
Дата: 20.05.05
:


G>

G>Ключевым моментом в паттерне Asynchronous Completion Token является то, что объект ACT, в общем случае, является непрозрачным для сервера (т.е. сервер совершенно не знает, что именно находится в ACT).


G>Если же учитывать Ваше же:

G>

G>А кто сказал, что нет. Есть Как и информация о том, что этот тип производен от базового типа.

G>То всё решается просто:

G>1. Есть некий ACTBase. От этого класса каждое звено цепочки пораждает свой — такой какой ей хочеться — ACT.

G>2. Сам ACTBase нечто похожее на:
<...>

Практически так, только, имхо, не очень правильно в базовый тип запихивать _previousACT, т.к. для многих ACT (у end-point-ов) вообще не будет _previousACT. Скорее здесь напрашивается такая иерархия:
class ACTBase { ... };
class ACTWithPrevious : ACTBase { ACTBase _previousACT; ... }


G>Т.е., например, маршрутизатор, получив запрос от клиента, генерирует свой ACT к которому "прикалывает" ACT, полученый в запросе. ACT маршрутизатора уходит далее по цепочке. При возврате, каждое звено возвращает ACTBase.Previous от своего ACT.


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

G>>> Т.е. клиент, в этом случае должен сериализовать свой id как базовый тип. Просто потому, что какой смысл посылать на сервер данные с которыми сервер работать все раавно не сможет?!


E>>Чтобы получить их в том же самом виде обратно.


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


E>>Нет, как раз клиент десериализует свой идентификатор в ответном сообщении именно как свой тип.


G>Ну если маршрутизатор может сериализовать его как ACT клиента — тогда да... Еще раз... Если все про всех всё знают, в чем прикол?!


Прикол в том, что все знают про ACTBase, но не знают конкретных наследников ACTBase.

Вот здесь есть еще на эту тему: Re[15]: Формат конфигов
Автор: eao197
Дата: 29.06.05
.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[26]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 30.06.05 06:39
Оценка:
Здравствуйте, gbear, Вы писали:

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


<...в общем-то правильные вещи поскипаны...>

G>После чего с этой службой могут одновременно работать как старые клиенты, так и новые.


G>Или, опять "фишку не просёк"?


Нет, пока полет нормальный

Имхо, проблема здесь в том, что количество интерфейсов будет плодится и размножаться. При этом функциональность сервиса не то чтобы не расширяется. Я бы сказал, что она просто детализируется. И поэтому здесь речь идет не о том, как сделать еще один метод sendSMS, а как передать дополнительные параметры к уже реализованной функциональности.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[41]: Функциональные типы (параллельная ветка)
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 30.06.05 07:00
Оценка: +1 :))
Здравствуйте, Cyberax, Вы писали:

>> ПК>Ну-ну... Вызов одного и того же метода у всех элементов коллекции —

>> бессмысленно?
>> Это динамичская типизация. Многих тут просто кондражка хватит от
>> такого предложения.

C>Вы это о чем?


Да, это я совершенно о другом подумал.

C>Например, есть коллекция векторов (трехмерные векторы), у каждого нужно

C>вызвать фукнцию normalize. Как вы это сделаете с делегатами?

Видимо по этой причине вместо нормальных внутренних итераторов ввели в язык дурацкий foreach.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[28]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 30.06.05 07:02
Оценка: +1
Здравствуйте, gbear, Вы писали:

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


G>>> Просто, имхо, тот же пример с pdu_t прекрасно "ложиться" на шаблон Visitor — и никакие указатели и делегаты тут, собственно, не нужны. Если уж приспичило через делегаты, то тут надо подходить с точки зрения ФП...


E>>Да, можно через Visitor. А можно и без. В C++ есть свобода выбора, что хорошо.


G>Уважаемый... Пример с pdu_t, если я не ошибаюсь, приведён Вами на просьбу привести пример где это (работа с "голыми" указателями) нужно. А по всему выходит что это пример того где Вы это используете.


G>Есть разница...


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

Разговоры про C++ тараканов в моей голове и нежелания думать C#-кими категориями или применять другие паттерны для решения показаной мной задачи -- это все уже другие вопросы.

Равно как и моя репрезентативность в поиске ситуаций, в которых указатели на методы можно применять, а делегаты -- нет. В мире около трех миллионов C++ программистов и я всего лишь один из них, причем далеко не самый продвинутый или эрудированный. Я лишь привел пример из своей недавней практики.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[27]: Функциональные типы (параллельная ветка)
От: gbear Россия  
Дата: 30.06.05 07:04
Оценка: +2
Здравствуйте, eao197, Вы писали:

E>Имхо, проблема здесь в том, что количество интерфейсов будет плодится и размножаться. При этом функциональность сервиса не то чтобы не расширяется. Я бы сказал, что она просто детализируется. И поэтому здесь речь идет не о том, как сделать еще один метод sendSMS, а как передать дополнительные параметры к уже реализованной функциональности.


Значит, таки, не просёк...

Т.к. по мне весь сыр бор вокруг того, как бы сделать так, что бы сервер имел один — вроде как неизменяемый — публичный интерфейс. В .NET в аналогичных случаях (traits map) с кондачка обычно используют DataSet как универсальное средство переноса параметров... Но. Как говАривал один мой преподаватель: "Посмотрите на амфибию... универсальное транспортное средство... одинаково плохо ездит и плавает".

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

Далее... Вот эта строчка меня особенно порадовала:

Изменение прототипа функции send_sms для удовлетворения возрастающих потребностей является тупиковым вариантом:


Т.е. подразумевается, что использовать — по сути — структуру с двадцатью параметрами, которую потом передавать в ф-цию с одим параметром более удобно?

Так, есть ли смысл, в средстве, которое поддалкивает к откровенно никудышному дизайну?

В топике про маршрутизацию продолжу мысль...

---
С уважением, Сиваков Константин.
Re[24]: Функциональные типы (параллельная ветка)
От: vdimas Россия  
Дата: 30.06.05 07:19
Оценка: +1
Здравствуйте, gbear, Вы писали:

G>Мягко говоря не совсем так... Даже в таком тупом примере, я вам показал делегат, который одновременно связан и с t.Format() и с с.Format.


G>Еще раз, но другими словами...



G>
G>            Drive c = new Drive();
G>            Text t = new Text();
G>            FormatDelegate dd = new FormatDelegate(c.Format); //Создали делегат, связанный с "c.Format"
G>            FormatDelegate td = new FormatDelegate(t.Format); //Создали делегат, связанный с "t.Format"
G>            FormatDelegate tdd = dd + td; //А этот делегат связан с уже и с тем и с другим.
G>            tdd(); //c.Format + t.Format;
G>            tdd -= dd; //Теперь ttd связан только с "t.Format";
G>            tdd();
G>            tdd -= td;// А теперь tdd не связан уже ни с чем. Т.е. равен null.
G>            if(tdd == null)
G>                Console.WriteLine("tdd is null");
G>            Console.ReadLine();
G>



Твой пример, все-таки, никак не решает вот эту задачу: http://www.rsdn.ru/Forum/Message.aspx?mid=1247965&amp;only=1
Автор: vdimas
Дата: 29.06.05


Я знаю, как решать подобную задачу на дотнет, но этот велосипед более громоздкий, чем аналогичный из С++, где подобная функциональность достигается одной строкой.

E>>PS

E>>Просьба не апелировать к тому, что экземпляры указателей на методы без объектов не нужны. Я их использую, значит мне нужны. И, имхо, их использую не только я.

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


Пример по ссылке подойдет?

G>Далее, собственно, по существу...


G>1. Поскольку делегат (как тип), ко всему прочему не превязан к конкретному типу — в отличие от... то он, таки, имхо, более общ.


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

Вот тут пара мыслей об "общности": http://www.rsdn.ru/Forum/Message.aspx?mid=1247806&amp;only=1
Автор: vdimas
Дата: 29.06.05


G>2. Для того функционала (пункты 1 и 2) делегаты, собсвенно не нужны... Вот как это выглядит на "голом" рефлекшене:


так стоп, фичи языка и рефлекшен не будем смешивать, ok? С помощью reflection можно полдучить небезопасный код, мне это Влад уже доказал. Да и вообще — рефлекшн желательно использовать только тогда, когда других путей нет. (И аргумент о низкой эффективности — далеко не самый главный здесь, "хакерский" подход накладывает ограничение на его использование, скажем так, это допустимо, например для библиотек уровня некоего фреймворка или кодогенерации, a использование его "непосредственно" — это ОЧЕНЬ плохой стиль)


[... тут код использования рефлекшена]
G>Устроит?

Нет, в случае статических методов не будет работать. А если захочешь расширить свой пример с рефлекшеном до более-менее универсального библиотечного варианта — то это на порядок больше кода — т.е. очередной велосипед.
Re[29]: Функциональные типы (параллельная ветка)
От: gbear Россия  
Дата: 30.06.05 07:25
Оценка: 20 (1) +2
Здравствуйте, eao197, Вы писали:

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


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

E>Равно как и моя репрезентативность в поиске ситуаций, в которых указатели на методы можно применять, а делегаты -- нет. В мире около трех миллионов C++ программистов и я всего лишь один из них, причем далеко не самый продвинутый или эрудированный. Я лишь привел пример из своей недавней практики.


Да блин... Вопрос, по крайней мере для меня, не в можно/не можно... А надо/не надо. Пока всё что я видел на "голых" ссылках — это:
1. Откровенно плохой дизайн.
2. Решается другими способами... без делатов и ссылок на методы.

Из этого-то мне и не понятно, зачем вообще нужны такие "голые" ссылки?! Провоцировать неокрепшие души на плохой дизайн... на использование их просто, потому что они есть? Потому что это, типа, модно?
---
С уважением, Сиваков Константин.
Re[25]: Функциональные типы (параллельная ветка)
От: vdimas Россия  
Дата: 30.06.05 07:36
Оценка: 2 (2) +1
Здравствуйте, eao197, Вы писали:


E>Надеюсь, что ты прочитал остальные сообщения топика и видел мой пример. Поэтому скажу, что голый указатель, естественно, рано или поздно, так или иначе связывается с конкретным объектом для проведения вызова. Мне же нужно, чтобы экземпляр указателя на метод появился до того как появится конкретный объект. Вот ты привел выше пример делегата из которого вычли все, что в нем было. Но для того, чтобы использовать этот экземпляр делегата с другим объектом, скажем d, я должен буду сделать:

E>
E>tdd += new FormatDelegate(d.Format);
E>


Тебя нагло обманывают

tdd += new FormatDelegate(d.Format);

Результат это выражения — новый экземпляр делегата (если null было до этого). А если кто-то владеет каким-либо экземпляром делегата, то он и продолжит им владеть, вот в чем грабли-то, и все твои новые Deleagate.Combine() пойдут очень даже мимо. Т.е. однажды отписавшись от него ты можешь не подписаться снова.

E>т.е. я явно должен буду указать, что от объекта d мне нужен именно метод Format, а не FormatVer1_2 или QuickFormat. А мне бы хотелось, чтобы в одном месте, без объектов, сначала определили Format, FormatVer1_2 или QuickFormat будет вызываться, а уже затем, в другом месте применяли это вызов к конкретному объекту.


Да, именно, behavior-паттерны на этом и держатся. В C# эту задачу можно решить без вызова через рефлекшен, тут 2 пути:

1. На каждую сигнатуру ф-ии ручками написать класс-переходник у котого:
— событие — агрегат для делегатов
— метод — переходник для некоего "внешнего" делегата, внутри метода надо вызвать событие (проверив его на null предварительно)

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

2. Заниматься кодогенерацией в run-time, т.е. генерить байт-код, исполняющий указанное. Если будет множество задач и множество различных сигнатур методов, то это — единственный приемлимый способ

Вот такие пироги. Тогда как в С++ — это более чем естественная и тривиальная задача.

G>>1. Поскольку делегат (как тип), ко всему прочему не превязан к конкретному типу — в отличие от... то он, таки, имхо, более общ.


E>Лично я не понял этого аргумента совершенно. Тип, который не привязан к конкретному типу -- это можно более простыми словами, мне, сирому, объяснить?


Ну, тут у товарища мысли вслух
Re[28]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 30.06.05 07:42
Оценка: 1 (1)
Здравствуйте, gbear, Вы писали:

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


E>>Имхо, проблема здесь в том, что количество интерфейсов будет плодится и размножаться. При этом функциональность сервиса не то чтобы не расширяется. Я бы сказал, что она просто детализируется. И поэтому здесь речь идет не о том, как сделать еще один метод sendSMS, а как передать дополнительные параметры к уже реализованной функциональности.


G>Значит, таки, не просёк...


G>Т.к. по мне весь сыр бор вокруг того, как бы сделать так, что бы сервер имел один — вроде как неизменяемый — публичный интерфейс. В .NET в аналогичных случаях (traits map) с кондачка обычно используют DataSet как универсальное средство переноса параметров... Но. Как говАривал один мой преподаватель: "Посмотрите на амфибию... универсальное транспортное средство... одинаково плохо ездит и плавает".


Так вот можно сказать, что я и предлагаю такой DataSet для C++.
А про амфибию можно мысль прояснить, а то я не понял что именно отождествляется с амфибией.

G>В любом случае, такое решение предпологает наличие на серверной сороне кода (в том или ином виде...) определяющего какие именно параметры переданы в функцию. Так? Оно нам действительно надо?! Имхо, декларативность в этом случае самое оно.


Именно, что на серверной стороне и для клиентов оно не видно.

G>

G>Изменение прототипа функции send_sms для удовлетворения возрастающих потребностей является тупиковым вариантом:

G>

    G>
  • количество назначаемых дополнительных параметров может достигать нескольких десятков (причем в различных сочетаниях). Использование же при программировании функции, в чей прототип входит, например, двадцать параметров, выглядит нереальным;


G>Т.е. подразумевается, что использовать — по сути — структуру с двадцатью параметрами, которую потом передавать в ф-цию с одим параметром более удобно?

G>Так, есть ли смысл, в средстве, которое поддалкивает к откровенно никудышному дизайну?

Может быть "никудышный дизайн" -- это уже универсальная отмазка?

Вот в протоколе Short Message Peer-to-Peer v.3.4 в команде submit_sm определены 28 необязательных параметров.
А в версии v.5.0 уже 44 параметра. Не считая еще 18 обязательных, из которых конечному пользователю нужны от силы 3-4. И вот если представить, что 44 необязательных и 18 полуобязательных параметров могут быть заданы в произвольном сочетании, то передача в функцию send_sms структуры с несколькими фиксированными полями и map-ом (можно назвать это DataSet-ом) лично мне представляется более жизнеспособным вариантом, чем попытка представить это все на уровне сигнатур методов какого-то интерфейса.

Равно как и организация visitora с 60-тью методами для проверки различных параметров команды submit_sm.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[25]: Функциональные типы (параллельная ветка)
От: gbear Россия  
Дата: 30.06.05 07:49
Оценка: +1
Здравствуйте, vdimas, Вы писали:

V>Твой пример, все-таки, никак не решает вот эту задачу: http://www.rsdn.ru/Forum/Message.aspx?mid=1247965&amp;only=1
Автор: vdimas
Дата: 29.06.05

V>Я знаю, как решать подобную задачу на дотнет, но этот велосипед более громоздкий, чем аналогичный из С++, где подобная функциональность достигается одной строкой.

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

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


V>Пример по ссылке подойдет?


См. выше...

G>>Далее, собственно, по существу...


G>>1. Поскольку делегат (как тип), ко всему прочему не превязан к конкретному типу — в отличие от... то он, таки, имхо, более общ.


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


Более общ по стравнению с "голым" указателем... В том смысле, что тип делегата не связан с типом делегируемого объекта.

V>Вот тут пара мыслей об "общности": http://www.rsdn.ru/Forum/Message.aspx?mid=1247806&amp;only=1
Автор: vdimas
Дата: 29.06.05


Спасибо... читали. Просто это дисскусия слепого с глухим. Вам говорят о том, что уж если "около трех миллионов" программистов постоянно изобретают велосипед на тему, то почему бы не включить этот велосипед в язык. Миллионы мух, как известно, ошибаться не могут. А три миллиона программистов, по всему выходит, что ошибаются... Так чтоль?

G>>2. Для того функционала (пункты 1 и 2) делегаты, собсвенно не нужны... Вот как это выглядит на "голом" рефлекшене:


V>так стоп, фичи языка и рефлекшен не будем смешивать, ok? С помощью reflection можно полдучить небезопасный код, мне это Влад уже доказал.


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

V>Да и вообще — рефлекшн желательно использовать только тогда, когда других путей нет. (И аргумент о низкой эффективности — далеко не самый главный здесь, "хакерский" подход накладывает ограничение на его использование, скажем так, это допустимо, например для библиотек уровня некоего фреймворка или кодогенерации, a использование его "непосредственно" — это ОЧЕНЬ плохой стиль)


Да ктоб спорил-то?! Повторюсь (здесь
Автор: gbear
Дата: 30.06.05
):


Да блин... Вопрос, по крайней мере для меня, не в можно/не можно... А надо/не надо. Пока всё что я видел на "голых" ссылках — это:
1. Откровенно плохой дизайн.
2. Решается другими способами... без делатов и ссылок на методы.

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


---
С уважением, Сиваков Константин.
Re[21]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.06.05 07:54
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Слово "пользовательский" — ключевое. Аттрибуты сами по себе ничего не делают, кто должен что-то сделать для их использования. Ничем не хуже мини-велосипедов для С++.


Отличие пользовательского кода в том, что он пишется несколько раз. Но, впрочем, и код, который это все реализует тоже несложен. Вот, собственно, он весь:
/// <summary>
/// Управляет вызовом обработчиков команд и обновления UI
/// </summary>
public class StripEventDispatcher
{
    //обработчики комманд 
    private Hashtable _actionHandlers = new Hashtable();

    public StripEventDispatcher(object handler)
    {
        Initialize(handler);
    }

    //Составляет карты обработчиков команд и обновления UI
    private void Initialize(object obj)
    {
        //выдираем методы 
        MethodInfo[] methods = obj.GetType().GetMethods(
            BindingFlags.DeclaredOnly |
                BindingFlags.Instance |
                BindingFlags.Public |
                BindingFlags.NonPublic);

        //пробегаем по списку методов
        foreach (MethodInfo method in methods)
        {
            //получаем Attribute для метода
            StripEventHandlerAttribute attr = 
                (StripEventHandlerAttribute)Attribute.GetCustomAttribute(
                    method, typeof (StripEventHandlerAttribute));

            //если таковой имеется
            if (attr != null)
                //создаем делегата обработчика и запихиваем в карту 
                //обработчиков комманд
                _actionHandlers[attr.EventId] = Delegate.CreateDelegate(
                    typeof (StripActionDelegate), obj, method.Name);
        }
    }

    //вызывает обработчик команды с переданным eventId
    public void DispatchEvent(string eventId)
    {
        if (_actionHandlers.Contains(eventId))
            ((StripActionDelegate) _actionHandlers[eventId])();
    }

    /// <summary>
    /// Метод, обработчик события Click кнопок.
    /// </summary>
    public void ClickHandler(object sender, EventArgs e)
    {
        DispatchEvent(((StripItemInfo)((ToolStripItem)sender).Tag).EventId);
    }
}
... << RSDN@Home 1.2.0 alpha rev. 505>>
AVK Blog
Re[29]: Функциональные типы (параллельная ветка)
От: gbear Россия  
Дата: 30.06.05 08:00
Оценка:
Здравствуйте, eao197, Вы писали:


E>Так вот можно сказать, что я и предлагаю такой DataSet для C++.

E>А про амфибию можно мысль прояснить, а то я не понял что именно отождествляется с амфибией.

DataSet, как универсальное средство переноса параметров... Необоснованное использование таких "амфибий" приводит к... скажем так, трудно сопровождаемым системам.

В смысле, ездить и плавать — будет. Но вопрос разве только в этом?

G>>В любом случае, такое решение предпологает наличие на серверной сороне кода (в том или ином виде...) определяющего какие именно параметры переданы в функцию. Так? Оно нам действительно надо?! Имхо, декларативность в этом случае самое оно.


E>Именно, что на серверной стороне и для клиентов оно не видно.


Да шайтан с ним, с клиентом... Просто этот код — сплошной кусок потенциального геморроя.

G>>Так, есть ли смысл, в средстве, которое поддалкивает к откровенно никудышному дизайну?


E>Может быть "никудышный дизайн" -- это уже универсальная отмазка?


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

---
С уважением, Сиваков Константин.
Re[27]: Функциональные типы (параллельная ветка)
От: vdimas Россия  
Дата: 30.06.05 08:07
Оценка: 1 (1) -1 :)
Здравствуйте, VladD2, Вы писали:

VD>Именно что пониманию мешает засевший в создании паттерн. А тут просто другой подход. И для понимания унжно принять другое решение. Глядеть на делегат как на единую сущьность, а не как на пару указателя на объект и указателя на метод.


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

— предположим, что мы меняем динамически поведение некоей сущности путем замены некоего имплементирующего экземпляра.
— предположим, что нам для этого нужен лишь 1 метод и мы не хотим городить целый интерфейс ради сигнатуры одного метода
— предположим, что мы используем непосредственно делегат и уже куда-то его передали.
— там, куда мы его передали могли сделать Delegate.Combine() с кучей других, неизвестных нам "мест".

Что дальше?

VD>Действительно говоря о делегате логически речь идет о ссылке на рантаймную сущьность — метод экземпляра. Это не более узкое решени или не более широкое, а прост другое.


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

VD>Далее остается только понять, что данную ссылку можно получить в рантайме в любой момент. Причем как в лучших традициях С++ с помощью статического кода, так и динамически через рефлекшон или от другого компонента.


Ну, понять это не трудно
А можно вопрос — в рантайме зачем? (т.е. через рефлекшен, а не код)
Только по существу плиз.

(Вопрос из области — кто кем владеет и кто кого подписывает на события, т.е. из области дизайна)

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


Я вот никогда не понимал этой твоей любимой фразы в конце чуть ли не каждого поста.
Ибо даже для реального использования предмета обсуждения нужно делать 4 действия:

1. public delegate void MyDelegate(Type1 arg1);
2. public event MyDelegate SomeEvent;
3. someObj.SomeEvent += new MyDelegate(someObj2, someMethod2);
4. protected void OnSomeEvent(Type1 arg1) { if(SomeEvent!=null) SomeEvent(arg1); }

При использовании любой библиотеки слотов и сигналов у нас ровно столько же действий.
На примере своей:

1. typedef void MyFuncType(Type1 arg);
2. Event<MyFuncType> SomeEvent;
3. someObj.SomeEvent.Hook(someObj2, someMethod2); — сюда идет любой someObj2 с подходящей сигнатурой someMethod2, ибо Hook — шаблонный.
4. void OnSomeEvent(Type1 arg1) { SomeEvent(arg1); }

Итого — все еще проще и никаких дополнительный действий делать не нужно.
Re[30]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 30.06.05 08:14
Оценка:
Здравствуйте, gbear, Вы писали:

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



E>>Так вот можно сказать, что я и предлагаю такой DataSet для C++.

E>>А про амфибию можно мысль прояснить, а то я не понял что именно отождествляется с амфибией.

G>DataSet, как универсальное средство переноса параметров... Необоснованное использование таких "амфибий" приводит к... скажем так, трудно сопровождаемым системам.


G>В смысле, ездить и плавать — будет. Но вопрос разве только в этом?


А ведь в том же SMPP и во многих GSM протоколах что-то подобное (типа DataSet, но там это TLV называется, из ASN1) давно и, что самое главное, успешно используется. Причем, зачастую, в условиях низких скоростей и органиченных вычислительных возможностей.

G>>>В любом случае, такое решение предпологает наличие на серверной сороне кода (в том или ином виде...) определяющего какие именно параметры переданы в функцию. Так? Оно нам действительно надо?! Имхо, декларативность в этом случае самое оно.


E>>Именно, что на серверной стороне и для клиентов оно не видно.


G>Да шайтан с ним, с клиентом... Просто этот код — сплошной кусок потенциального геморроя.


Бывает так, что этот геморрой уже "дан нам в ощущениях", как объективная реальность Например, когда работаешь с протоколами типа SMPP или GSM, не ты определяешь правила игры.

Кстати, геморрой этот -- это на первый взгляд только. Если правильно организовать структуры данных, например, тот же map сделать для опциональных TLV полей, то вообще никаких проблем -- обрабатываещь то, что можешь и умеешь, а остальное просто сериализуещь/десериализуешь. Причем извлечение чего-то из map может напоминать работу с XPath -- вытаскиваешь из множества данных именно то, что нужно.

G>>>Так, есть ли смысл, в средстве, которое поддалкивает к откровенно никудышному дизайну?


E>>Может быть "никудышный дизайн" -- это уже универсальная отмазка?


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


Вообще-то статья была не про дизайн, а про инструмент, который дается в руки разработчику. А уже как им разработчик будет распоряжаться... Книгами, например, орехи колоть тоже можно. А когда молотка или чего-то подобного под рукой нет, это вообще окажется единственно возможным решением.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[24]: Функциональные типы (параллельная ветка)
От: vdimas Россия  
Дата: 30.06.05 08:42
Оценка: 1 (1) +2
Здравствуйте, VladD2, Вы писали:


VD>Примеры, в студию, что можно сделать этим "более общим" механизмом.



VD>И пример в студию как этим общим механизмом положить в один массив указатели на методы разных классов.


вот:
typedef void MyFunc(Type1 arg);

struct s1 { void f1(Type1 arg) {} }

struct s2 { void f2(Type1 arg) {} }

std::vector<Functor<MyFunc>*> vec;
vec.push_back(new Delegate<s1, Myfunc>(new s1(), s1::f1));
vec.push_back(new Delegate<s2, Myfunc>(new s2(), s1::f1));


E>>1) позволяет как связать указатель с конкретным объектом (посредством дополнительных оберток, как в моем примере или средствами boost-а),


VD>А зачем тут шаблоны то? Тип метода не изменяется ведь.


Ты был бы прав, при отсутствии множественного наследования. Расказать, как именно тип метода меняется, или сам понимаешь?

Кстати, еще могут быть разные call convertions у методов, и их наследие — ну никак не недостаток С++, они просто есть вокруг нас. И это все неплохо объединяют шаблонные обертки, в одно движение, так же как в дотнет.

Я вот не могу понять, с чем именно ты споришь? Тот факт, что все дотнетное, которое доступно нам средствами языка C#, делается в С++ ровно во столько же действий, тебе уже продемонстрировали. Тебе просто не нравится сам факт, что мы для этого пользуем быблиотеку, а не фичи языка? А как это сказывается на процессе разработки, понимании программы или потребительских качествах готового продукта?

Ты бы хоть посмотрел на ту же Java и задался бы вопросом — а почему вообще в C# ввели делегаты? И почему именно так? (учитывая "управляемость среды")
А когда найдешь эти причины, оцени — насколько они актуальны для С++? Ты же сейчас следствия за причины пытаешься нам выдать.

Короче, поинт спора в чем???

E>>2) создавать экземпляр указателя на конкретный нестатический метод без наличия самого объекта.


VD>Зачем?!!!


И снова пошли ходоки к Ленину: http://www.rsdn.ru/Forum/Message.aspx?mid=1247965&amp;only=1
Автор: vdimas
Дата: 29.06.05


E>>В C# п.1 получается автоматом, т.к. для этого есть поддержка со стороны компилятора. В C++, можно сказать, такая поддержка так же есть со стороны boost.


VD>Заплатка это а не поддержка.


Ты не прав. Фича языка на какую-то отдельную концепцию, и является заплаткой, если эта концепция не представима в терминах языка. Все, что легко реализуется средствами языка не требует заплаток изначально. Ключевые слова: "не легко" -> "заплатка".

Попробуй выразить функциональность делегата без этой фичи языка на C#? Получилось? То-то

Вот тебе и причина, и хватит ставить все с ног на голову.


E>>Просьба не апелировать к тому, что экземпляры указателей на методы без объектов не нужны. Я их использую, значит мне нужны. И, имхо, их использую не только я.


VD>Чущь, именно к этому и нужно апеллировать, так как ты использушь их исключительно в связке с конкретными указателями на объекты. И никогда без них.


Да, но мы можем подставлять конкретные экземпляры.

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

Или, например, есть такое дело как диспечеризация. Можно "забить" одну сигнатуру некоей общей ф-ии в некоем общем интерфейсе. А затем, в run-time делать кучу if или case для выбора реальной имплементации. Но можно просто подать указатель на нужный метод и потом сразу вызывать именно его. Целесообразность такой вещи зависит от количества if и case, согласись.

Паттерн визитор или же двойная диспечеризация не всегда подходят для подобного случая, ибо визитор в компайл-тайм должен знать обо всех используемых типах и используемых методах, вот тебе еще причина.
Re[26]: Функциональные типы (параллельная ветка)
От: vdimas Россия  
Дата: 30.06.05 09:10
Оценка: 5 (3) +1
Здравствуйте, gbear, Вы писали:

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

G>Просветите — тогда и поговорим.

Ты очень правильно выделил слово необходимы. Известно, что любая задача решается множеством способов, и чем этот способ проще — тем лучше.

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

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

Теперь просветил?

G>Более общ по стравнению с "голым" указателем... В том смысле, что тип делегата не связан с типом делегируемого объекта.


Замечательно, а некий шаблон, требующий у типа-параметра лишь operator() — разве не более общее решение (не возможное в дотнет, кстати)? Ведь под этот параметр лезут и глобальные ф-ии, и статические и объекты-функторы и ссылки на таковые (И переходники-делегаты в т.ч. как частный случай функционального объекта)

G>Спасибо... читали. Просто это дисскусия слепого с глухим. Вам говорят о том, что уж если "около трех миллионов" программистов постоянно изобретают велосипед на тему, то почему бы не включить этот велосипед в язык. Миллионы мух, как известно, ошибаться не могут. А три миллиона программистов, по всему выходит, что ошибаются... Так чтоль?


А может составим более подробный список, чего уж там мелочиться? Да в язык можно еще столько всякой хрени воткнуть А ты там о каких-то несчастных делегатах. Ну НЕ ПРОБЛЕМА ЭТО, понимаешь. Действительно, разговор слепого с глухим.

Не это сейчас срочно для С++. Ведь ЭТО уже есть и работает и требует ровно столько же строк как в дотнете. Чего же еще надо? И давно никто свои велосипеды не пишет, они были написаны ЗАДОЛГО до дотнета, вот ведь какие дела. Теперь лишь вылизывают тот велосипед, который будет стандартом.

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


G>>>2. Для того функционала (пункты 1 и 2) делегаты, собсвенно не нужны... Вот как это выглядит на "голом" рефлекшене:


V>>так стоп, фичи языка и рефлекшен не будем смешивать, ok? С помощью reflection можно полдучить небезопасный код, мне это Влад уже доказал.


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


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

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

V>>Да и вообще — рефлекшн желательно использовать только тогда, когда других путей нет. (И аргумент о низкой эффективности — далеко не самый главный здесь, "хакерский" подход накладывает ограничение на его использование, скажем так, это допустимо, например для библиотек уровня некоего фреймворка или кодогенерации, a использование его "непосредственно" — это ОЧЕНЬ плохой стиль)


G>Да ктоб спорил-то?! Повторюсь (здесь
Автор: gbear
Дата: 30.06.05
):



G>

G>Да блин... Вопрос, по крайней мере для меня, не в можно/не можно... А надо/не надо. Пока всё что я видел на "голых" ссылках — это:
G>1. Откровенно плохой дизайн.
G>2. Решается другими способами... без делатов и ссылок на методы.

G>Из этого-то мне и не понятно, зачем вообще нужны такие "голые" ссылки?! Провоцировать неокрепшие души на плохой дизайн... на использование их просто, потому что они есть? Потому что это, типа, модно?


К выражению "плохой дизайн" тут немного чуствительны. Можно пару слов о сути виденных тобой ошибках дизайна?
Re[24]: Функциональные типы (параллельная ветка)
От: vdimas Россия  
Дата: 30.06.05 09:37
Оценка:
Здравствуйте, VladD2, Вы писали:

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


Черт, в пылу спора забыли самое главное. В дотнете мы подаем для образования делегата не любой тип, а наследник от System::Object. (собственно, в сигнатуре конструктора делегата требуется именно этот тип)

Если в С++ вывести свою иерархию от некоего базового
struct Object {};

то сможем так же смело обращаться с указателями на методы.

и "совместимый" делегат будет лишь один, и пользоваться им достаточно будет так:

typedef Delegate<void(type1, type2)> MyDelegate;


А вот она и имплементация для этой иерархии:
(Интересно, насколько актуально внесение этой ерунды в язык )
template<typename funcT>
struct Delegate {};

template<> struct Delegate<void()> {
    typedef void (Object::*FuncType)();

    Delegate(Object* o, FuncType f) : target(o), func(f) {}
    void operator()() { (target::*func)(); }

    Object* target;
    FuncType func;
}

template<typename paramT> struct Delegate<void(paramT)> {
    typedef void (Object::*FuncType)();

    Delegate(Object* o, FuncType f) : target(o), func(f) {}
    void operator()(paramT p1) { (target::*func)(p1); }

    Object* target;
    FuncType func;
}

// и т.д.


Вот и все!!!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.