Здравствуйте, VladD2, Вы писали:
VD>Продемонстрируй мне, плиз, на любом языке (на шпрпе так вообще замечательно бедет) как меняется контекст от вызова.
Для начала определю, что контекст — это множество пар <имя, область хранения>, т.е множество биндингов. Наверное, это следовало бы сделать сразу.
Возьмем код, приведенный выше:
using System;
public class Test
{
public delegate int retInc();
public static void Main(string[] args) {
retInc func = create();
retInc func2 = create();
Console.WriteLine(func());
Console.WriteLine(func2());
}
public static retInc create() {
int val = 0;
return delegate () {
return val++;
};
}
}
Этот код выведет два раза 0. Почему? Потому что оба раза, когда создавались замыкания (при первом вызове create и при втором) контекст был _разный_, т.е переменная — одна (одно имя), но при двух разных вызовах переменная связывалась с разными областями хранения (с точки зрения семантики, детали реализации не интерсны). Если бы мы создали оба замыкания во время одного вызова create:
using System;
public class Test
{
public delegate int retInc();
public static void Main(string[] args) {
retInc func1, func2;
create(out func1, out func2);
Console.WriteLine(func1());
Console.WriteLine(func2());
}
public static void create(out retInc f1, out retInc f2) {
int val = 0;
f1 = delegate () {
return val++;
};
f2 = delegate () {
return val++;
};
}
}
То контекст у обоих замыканий был бы один и тот же, как результат — получаем вывод 0 и 1.
>Мне этот спор надоел. Думаю ты понял о чем я говорю.
Здравствуйте, VladD2, Вы писали:
VD>Чтобы вставить делегаты (клозюры, функциональный тип и т.п.) не нужна какая-то сверхестественная модификация языка. Нужно ввести новый тип указателя. Синтаксис будет практически таким же как при работе с указателями на глобальные функции. Ну, и нужно разрешить объявлять анонимные функции. Это очень небольшие изменения. И просто вселенской глупостью будет если комитет откажется от этого и узаконит бустовскую эмуляцию.
Замыкание != делегаты. Для полноценных замыканий необходимо обеспечить возможность захвата контекста вызова.
Я думаю, в случае с C++ основная проблема будет со стековыми переменными. Например, в следующем коде время жизни локальной val продляется до времени жизни делегата.
using System;
public class Test
{
public delegate int retInc();
public static void Main(string[] args) {
retInc func = create();
retInc func2 = create();
Console.WriteLine(func());
Console.WriteLine(func());
Console.WriteLine(func2());
}
public static retInc create() {
int val = 0;
return delegate () {
return val++;
};
}
}
В .NET это решается созданием специального класса, хранящего контекст, используемый в делегате. Т.е переменная val на самом деле будет полем специального объекта, который будет создан в начале вызова метода. И ссылка на этот объект (представляющий собой контекст) будет передана неявная делегату.
В случае C++, мне кажется, такое сделать будет сложнее. В основном, наверное, из-за отсутствия сборщика мусора. Например, если мы помещаем контекст (грубо говоря, локальные переменные) в кучу, то непонятно когда его удалять — он должен жить пока есть хоть один делегат, ссылающийся на него.
То есть если мы в функции create создадим десяток делегатов подряд, использующих одну локальную переменную val (и соотвественно имеющих общий контекст), то контекст должен быть удален только если все делегаты уже умерли.
Собственно, это фишка и называется "замыкание" (возвращаясь к теме замыканий vs делегаты ).
Здравствуйте, VladD2, Вы писали:
ПК>>В С++ далеко не обязательно вносить изменения в язык, чтоб поддержать нечто, идентичное по удобству использования делегатам C#. Скажем, boost::function не уступают ни капельки.
VD>Уступают, уступают. И еще как.
А именно, как? Опиши конкретно, по пунктам. (не затрагивая лямбда-функции, что является разговором отдельным и, очевидно, требует языковой поддержки)
> Получается гора кода и немало ограничений.
Гора кода где, у пользователя? Если так -- примеры конкретных отличий с точки зрения использования, пожалуйста. В библиотеке не считается, т.к. что стандартная библиотека, что компилятор -- само по себе это с точки зрения пользователя безразлично.
ПК>>Это и было бы описываемым Страуструпом более общим решением, чем делегаты.
VD>Страуструп как всегда высказался в своем духе "мы даем людям универсальные абстракции вроде классов", типа другие не дают
Не дают. Указатель на функцию или указатель на член -- более базовая функциональность, чем делегаты, т.к. последние через первые реализовать можно, а наоборот -- нет.
VD>Пожизни же нужно сделать примитивную вещь. Ввести указатель на функцию объекта в котором будет и указатель на функцию, и указатель на объект. Для компиляторщиков делов на пол дня. Это будет работать быстро и эффктивно.
В чем конкретно будет разница с библиотечным решением? Без эмоций, только конкретные отличия, пожалуйста.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, VladD2, Вы писали:
VD>Нет. Для начала мы определимся, что контекст — это набор перепенных доступной и некоторой точки.
Тогда весь разговор смысла вообще не имеет. Потому как замыкания захватывают именно динамический контекст, так, как я его определил. Это и есть смысл замыканий — захват биндингов переменных (тех, которые находятся в области видимости) в рантайме. И "контекст" я употреблял именно в смысле биндингов.
VD>Все остальное соотвественно смысла не имеет.
Здравствуйте, Cyberax, Вы писали:
C>VladD2 wrote:
>> Ты очередной раз умудрился не понять, что я говорю. Еще раз. *Closur >> != анонимным методам* (или если угодно, *ламбдам*). Closur == делегат. >> И на этом уровне проблем вообще нет. Почитай хотя бы документацию по >> Дельфи.
C>В Дельфи нет замыканий, а есть делегаты, названные "замыканиями".
C>Вообще, вот статья: C>http://en.wikipedia.org/wiki/Closure_%28computer_science%29
Весь прикол в том, что свои, э-э-э..., убеждения Влад черпает именно из этой статьи.
eao197 wrote:
>>> А откуда слухи о появлении в C++ рефлекшена? > C>Это не слухи, Страуструп усиленно продвигает XTI еще с 99 года. > А точной ссылкой на описание XTI не поделишься?
People comparing languages using lists love such features. The snag is that the problems we face are essentially infinite, so we need an infinity of such specialized features. Examples are Pascal procedure parameters and C# delegates. The alternative traditionally offered by C++ (and before that by K&R C) is to provide very general features from which good programmers can construct solutions to a wide variety of problems. Examples are pointers and classes.
> ПК>Теперь объясни, как именно это исключает введение стандартных классов, представляющих function type? > > Стандарные классы без изменения языка — это маразм.
Очень доходчиво
> Зачем объходить проблемы лепя горы кода и получая совершенно неудобоваримый результат вместо того чтобы встроить в язык саму собой напрашивающуюся вещь?
В С++ далеко не обязательно вносить изменения в язык, чтоб поддержать нечто, идентичное по удобству использования делегатам C#. Скажем, boost::function не уступают ни капельки.
Введение аналога анонимных делегатов, aka лямбда-функций, действительно, потребует модификации языка. Но и здесь вводить новый тип, видимый пользователю, кроме boost::function, не нужно. Достаточно поддержать удобный синтаксис создания анонимных объектов анонимных классов с перегруженным operator() по месту использования. Что-нибудь в таком духе:
Здравствуйте, VladD2, Вы писали:
VD>Стандарные классы без изменения языка — это маразм. Зачем объходить проблемы лепя горы кода и получая совершенно неудобоваримый результат вместо того чтобы встроить в язык саму собой напрашивающуюся вещь?
Странное рассуждение. В C# весь reflection доступен так же в виде модели экземпляров классов-дескрипторов. Ничего такого в язык не вставлено. Если "узаконить" часть буста (типа как std::type_info), то зачастую, достаточно будет лишь небольшой поддержки компилятором без значительных изменений языка.
Павел Кузнецов wrote:
> ПК>>А именно, как? Опиши конкретно, по пунктам. (не затрагивая > лямбда-функции, что является разговором отдельным и, очевидно, требует > языковой поддержки) > VD>Начнем с того, что делегаты это намного больше чем просто > замыкание. Их можно объеденять. > Это делается легко и с boost::function и аналогами.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>А именно, как? Опиши конкретно, по пунктам. (не затрагивая лямбда-функции, что является разговором отдельным и, очевидно, требует языковой поддержки)
Начнем с того, что делегаты это намного больше чем просто замыкание. Их можно объеденять. Потом это полноценный компонентный тип. Его можно передать в другие компоненты, по сети и т.п. Его можно создать в рантайме. Они даже могут быть обобщенными. Ну, что-то вроде:
delegate bool Predicate<T>(T t);
Ну, и на его компиляцию практически не тратится времени.
>> Получается гора кода и немало ограничений.
ПК>Гора кода где, у пользователя?
У компилятора. Что неминуемо замедлид компиляцию.
ПК> Если так -- примеры конкретных отличий с точки зрения использования, пожалуйста.
О. Это легко. Создашь два аналогичных примера и нажимашь F5. Далее следишь за тем насколько скоро запустится отлаживаемый модуль. После этого можно попробовать передать boost::function по сети. Ну, в общем можешь и сам придумать.
ПК> В библиотеке не считается, т.к. что стандартная библиотека, что компилятор -- само по себе это с точки зрения пользователя безразлично.
Это если пользователю по барабану результат и удобство.
ПК>>>Это и было бы описываемым Страуструпом более общим решением, чем делегаты.
VD>>Страуструп как всегда высказался в своем духе "мы даем людям универсальные абстракции вроде классов", типа другие не дают
ПК>Не дают.
Что, классов нет? Вауу...
ПК> Указатель на функцию или указатель на член -- более базовая функциональность, чем делегаты, т.к. последние через первые реализовать можно, а наоборот -- нет.
Серьезно? А может поглядеть на эту реализацию? Это выкручивание, а не реализация. Основная проблема подобных реализаций это как раз обход излишне заботливого контроля типов.
Как раз делегатами можно решить все проблемы решаемые "указателем функцию на член", а вот обратное не верно. И выверты реализаций вроде boost::function это прекрасно демонстрируют.
Кстати, просто указатели на члены, и просто указатели на функции тут не причем. Они действительно универсальны и не содержат проблем.
ПК>В чем конкретно будет разница с библиотечным решением? Без эмоций, только конкретные отличия, пожалуйста.
Я уже много раз это говорил. Даже тормоза при компиляции это уже проблемы. А уж то, что это не первокласная функция услжнит жизнь не в одном месте. Например, если все же в С++ появится хоть какой-то рефлекшон, то анализ boost::function станет не хилой проблемой. Между тем анализ встроенного типа проблем не имеет.
В общем, дело не в виде который примет сам указатель. В том же шарпе делегат это тоже класс. Дело в поддежке со стороны компилятора и во внутренней реализации. Если это дело будет выглядеть как boost::function но при этом внутри появится хак, то многие проблемы исчезнут. Но куда логичнее просто ввести новый тип указателя и уже на его базе делать остальные решения.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
ПК>>А именно, как? Опиши конкретно, по пунктам. (не затрагивая лямбда-функции, что является разговором отдельным и, очевидно, требует языковой поддержки)
VD>Начнем с того, что делегаты это намного больше чем просто замыкание. Их можно объеденять.
Это делается легко и с boost::function и аналогами.
VD> Потом это полноценный компонентный тип. Его можно передать в другие компоненты, по сети и т.п. Его можно создать в рантайме.
Это уже ограничения среды исполнения: либо она поддерживает подобные вещи, либо нет. В C++ подобной поддержки (по крайней мере, в готовом виде) нет в принципе. От того, что boost::function стал бы, как ты предлагаешь, встроенным типом, эти аспекты бы ни на капельку не изменились бы.
VD> Они даже могут быть обобщенными. Ну, что-то вроде: VD>
VD>delegate bool Predicate<T>(T t);
VD>
Это и для boost::function верно.
VD>Ну, и на его компиляцию практически не тратится времени.
Намного более общим подходом является решение проблем скорости компиляции (введение поддержки модулей и т.д.), нежели введение в язык "хэков" для поддержки всевозможных популярных компонентов: boost::function, std::vector, std::list и т.п.
VD>В общем, дело не в виде который примет сам указатель. В том же шарпе делегат это тоже класс. Дело в поддежке со стороны компилятора и во внутренней реализации. Если это дело будет выглядеть как boost::function но при этом внутри появится хак, то многие проблемы исчезнут. Но куда логичнее просто ввести новый тип указателя и уже на его базе делать остальные решения.
В общем, дальше можно не продолжать: аргументация подобного уровня мне неинтересна.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
VladD2 wrote:
>>> C>данная проблема устранена в C# 2.0. > C>Которого еще нет в природе (до ноября, кажется?). > Который давно доступен для использоания. А нет его только для тех кто > сильно жмурится.
Релиза официального нет? Тогда свободны (а то я могу сказать, что TR1 и
XTI (eXtended Type Information) для С++ давно уже доступны — для тех кто
не жмурится).
> C>Угу, и самому делать мультикаст. Спасибо, благодарю. > Что там делать то? > >GetData getDataMulticast = f1 + (GetData)f2 + f3; > >int sum = 0; > >foreach (GetData getData in getDataMulticast.GetInvocationList()) > sum += getData(); > >
А если в процессе обработки getData произойдет изменение списка
слушателей? Так что пробуйте дальше.
> Что не сильно сложнее, но особого смысла не имеет.
Это только так кажется.
> C>А что вы имеете ввиду под "динамическим созданием"? > Возможность создать экземлпяр делегата в рантайме и привезать его к > произвольному методу не извесному на момент компиляции.
Опять, же нужен рефлекшн. Если возможный набор методов известен на этапе
компиляции, то делается элементарно и в С++.
> Это конечно тоже упирается в убогость рантайма С++, но если верить > слухам о появлении в плюсах в каком-то виде рефлекшона, то такая > возможность была бы очень востребована. Лично я очень часто использую > делегаты именно как решение рантаймных проблем.
Это скорее всего можно будет сделать.
> C>Каждый обработчик возвращает int, комбайнер запоминает максимум. При > значении больше 100 > C>досрочно прекращается вызов сигналов. > Здорово, но бессмысленно. А не нельзя ли создать осмысленный пример > кторый можно было бы а) описать, б) скопмилировать и запустить?
Можно, но код будет не сегодня — некогда. Опишу пример словами:
1. Есть сигнал и набор слушателей, слушатели разделяются на несколько
уровней приоритета (слушатели должны вызываться в порядке убывания
приоритета).
2. Каждый обработчик может запретить вызов дальнейших обработчиков.
3. Каждый обработчик возвращает целое число, после обработки всех
сигналов я должен получить список возвращенных значений.
Здравствуйте, VladD2, Вы писали:
VD>Мне кажется ты преувеличиваешь. Проблема многопоточного программирования — это отдельная проблема. Она существует без каких бы то нибыло дополнений. И единственный простой ее обход — это постоянно порождать копию данных (в общем использовать функциональный стиль). И тут как раз анонимные методы очень даже неплохо могут себя показать если не менять эти переменные внутри анонимных методов.
Ок, ты немного не понял о чем я.
Речь о другом. Есть некие устоявшиеся постулаты при работе с мультипоточными программами. Например — локальные переменные доступны лишь контексту текущего потока (т.к. стек — это приватный элемент потока). Далее, мы вводим анонимный делегат, который в начале не использует некие локальные переменные. После очередной доработки кто-то незаметно решил попользовать локальную переменную в анонимном коде делегата. И эта переменная незаметно перестала быть стековой. Собственно, в этом суть упомянутых граблей.
VD>Ну, а модификация переменных... Дык это общая проблема императивных языков. Так что если мы говорим о таком на сквозь императивном языке как С++, то рассуждать о потенциальной грабельности модификации переменных в многопоточных программах просто смешно.
Если уточнить, что речь о стековых переменных, то становится уже не смешно, а чуточку страшно. Локальный контекст — это вообще единственная точка опоры при многопоточном программировании.
VladD2 wrote:
> C>boost::signals — причем она намного лучше, чем делегаты в C#. Вот > C>сравнение: http://boost.org/doc/html/signals/s06.html#id575480 > Require exact type matches between a delegate and what it is calling. > Это проблема не дотнета а Шарпа 1.х. данная проблема устранена в C# 2.0.
Которого еще нет в природе (до ноября, кажется?).
> Only return the result of the last target called, with no option for > customization. > Вообще не проблема. Используй массив делегатов.
Угу, и самому делать мультикаст. Спасибо, благодарю.
> А вот про проблемы бинда почему то ни звука. А их не мало. Медленная > компиляция, невозможность анализа signal-а как единой сущьности > невозможность динамического создания сигналов и т.п.
Компиляция — это вообще проблема С++. А насчет анализа — когда он будет
в С++, то будут методы кастомизировать его, чтобы представлять сложные
объекты, как "единую сущность".
А что вы имеете ввиду под "динамическим созданием"?
> Кстати, забавно было бы сравнить код на делегатах и сигналах.
С мультикастом? Вполне:
struct push_max {
typedef int result_type;
push_max() : max_value(), got_first(false) {}
// returns false when we want to stopbool operator()(int result) {
if (!got_first) {
got_first = true;
max_value = result;
} else
if (result > max_value)
max_value = result;
if (result > 100)
return false;
return true;
}
int get_value() const
{
if (!got_first)
throw std::runtime_error("Empty!");
return max_value;
}
private:
int max_value;
bool got_first;
};
typedef boost::signals<int*(void), push_max> sig_type;
sig_type signal;
signal.connect(...);
signal.connect(...);
signal(); //Call signal!const push_max result=signal.combiner(); //Get combiner
Каждый обработчик возвращает int, комбайнер запоминает максимум. При значении больше 100
досрочно прекращается вызов сигналов.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>В С++ далеко не обязательно вносить изменения в язык, чтоб поддержать нечто, идентичное по удобству использования делегатам C#. Скажем, boost::function не уступают ни капельки.
Уступают, уступают. И еще как. А главное что это гора кода на ровном месте. Указатели на функции-члены в С++ идея плохая. Эмуляция на них нормальных функциональных типов соотвественно тоже. Получается гора кода и немало ограничений.
ПК>Введение аналога анонимных делегатов, aka лямбда-функций, действительно, потребует модификации языка. Но и здесь вводить новый тип, видимый пользователю, кроме boost::function, не нужно. Достаточно поддержать удобный синтаксис создания анонимных объектов анонимных классов с перегруженным operator() по месту использования. Что-нибудь в таком духе: ПК>
ПК>Это и было бы описываемым Страуструпом более общим решением, чем делегаты.
Страуструп как всегда высказался в своем духе "мы даем людям универсальные абстракции вроде классов", типа другие не дают .
Пожизни же нужно сделать примитивную вещь. Ввести указатель на функцию объекта в котором будет и указатель на функцию, и указатель на объект. Для компиляторщиков делов на пол дня. Это будет работать быстро и эффктивно. Ананоимные методы с возможностью получить доступ к внешним переменным тоже очень логичное расширение. Я бы еще добавил возможность описывать вложенные методы.
Все это привело бы к ускорению компиляции и упрощению библиотек и кода. При этом потерь никаких нет. Страуступ много лет назад объяснял решение ввести уродливые указатели на функции-члены борьбой за безопасность. При этом решение вроде делегатов он отвергал на отрез приписывая ему ненадежность. Сейчас же он уже вроде как не против эмуляции той же идиомы на горе шаблонов. И зачем? Может признать свою ошибку и сделать все как надо?
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, vdimas, Вы писали:
V>>Здравствуйте, VladD2, Вы писали:
VD>>>Стандарные классы без изменения языка — это маразм. Зачем объходить проблемы лепя горы кода и получая совершенно неудобоваримый результат вместо того чтобы встроить в язык саму собой напрашивающуюся вещь?
V>>Странное рассуждение. В C# весь reflection доступен так же в виде модели экземпляров классов-дескрипторов. Ничего такого в язык не вставлено.
VD>В C# есть делегаты и анонимные методы. Они полностью поддерживаются компилятором в следствии чего их очень просто и удобно использовать. Для компилятора такая поддержка ничего не стоит. А вот для программиста она дает практически молниеносную компиляцию.
V>> Если "узаконить" часть буста (типа как std::type_info), то зачастую, достаточно будет лишь небольшой поддержки компилятором без значительных изменений языка.
VD>Чтобы вставить делегаты (клозюры, функциональный тип и т.п.) не нужна какая-то сверхестественная модификация языка. Нужно ввести новый тип указателя. Синтаксис будет практически таким же как при работе с указателями на глобальные функции. Ну, и нужно разрешить объявлять анонимные функции. Это очень небольшие изменения. И просто вселенской глупостью будет если комитет откажется от этого и узаконит бустовскую эмуляцию.
Ну и как ты себе представляешь продление времени жизни локальных переменных, используемых анонимной ф-ий. Я прекрасно знаю, как это сделано в C# 2.0, тем не менее, на мой взгляд, это тааааакие грабли, при мультипоточном использовании подобных анонимных делегатов. Абсолютно неочевидные и гнусные грабли.
Здравствуйте, WFrag, Вы писали:
WF>Замыкание != делегаты.
Ошибаешся.
WF> Для полноценных замыканий необходимо обеспечить возможность захвата контекста вызова.
Еще раз ошибаешся. Не контекст вызова, а контекст функции. А это разные вещи. Для анонимной функции (лямбды) этот контекст зачастую действительно близок к контексту вызова, но это не обязательно. Так что всегда запоминается контекст описания. Было бы здорово если в С++ ввели анонимные методы, но сами замыкния или делегаты намного важнее.
Или это как раз тот слувай что описан в начале того сообщения ("гляжу в книгу — вижу фигу")?
WF>Я думаю, в случае с C++ основная проблема будет со стековыми переменными. Например, в следующем коде время жизни локальной val продляется до времени жизни делегата.
Проблемы в С++ несомненно будут. Но не технические, а проблемы с тараканами в мозгах его авторов.
WF>В случае C++, мне кажется, такое сделать будет сложнее. В основном, наверное, из-за отсутствия сборщика мусора. Например, если мы помещаем контекст (грубо говоря, локальные переменные) в кучу, то непонятно когда его удалять — он должен жить пока есть хоть один делегат, ссылающийся на него.
В С++ все не просто. Но если проблему решать, то она решается. Ту же скорее проблема в нежеланием решать проблемы. Вместо этого всем объясняется, что все проблемы можно решить библиотеками. Вот это мне и не нравится.
WF>То есть если мы в функции create создадим десяток делегатов подряд, использующих одну локальную переменную val (и соотвественно имеющих общий контекст), то контекст должен быть удален только если все делегаты уже умерли.
Делегаты не могут ссылаться на переменные. Делегаты — это ссылки на функции. Ссылаются сами функции. Сколько можно это повторять?
WF>Собственно, это фишка и называется "замыкание" (возвращаясь к теме замыканий vs делегаты ).
Да, уж. Возвращамся, хотя мне казалась эта тема закрытой.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VladD2,
> VD>> Они даже могут быть обобщенными. Ну, что-то вроде: > VD>>
> VD>>delegate bool Predicate<T>(T t);
> VD>>
> > ПК>Это и для boost::function верно. > > Возможно. Продемонстрируй, плиз, код.
boost::function<bool(T)> Predicate;
> В общем, я не вижу смысла решать проблемы метапрограммированием там где просто напрашивается введение примитива в язык.
В этом как раз и есть разница, о которой говорил Страуструп: в C++ не видят смысла вводить примитив в язык, если можно ввести возможность, позволяющую сделать ту же задачу с помощью создания библиотеки.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
VladD2 wrote:
> WF>Нет, я хочу сказать что проблема довольно серьезная и вряд ли > вообще решаема без серьезных изменений (например, GC). Поэтому твои > лихие слова о тараканах в голове мне и не нравятся. Не так все просто, > как мне кажется. > Ты очередной раз умудрился не понять, что я говорю. Еще раз. *Closur > != анонимным методам* (или если угодно, *ламбдам*). Closur == делегат. > И на этом уровне проблем вообще нет. Почитай хотя бы документацию по > Дельфи.
В Дельфи нет замыканий, а есть делегаты, названные "замыканиями".
Здравствуйте, Cyberax, Вы писали:
>> Only return the result of the last target called, with no option for >> customization. >> Вообще не проблема. Используй массив делегатов.
C>Угу, и самому делать мультикаст. Спасибо, благодарю.
Зачем? MulticastDelegate.GetInvoсationList() еще никто не отменял. Вобщем нет этой проблемы в дотнете, есть плохое знание авторами сего текста этих самых делегатов.
C>А что вы имеете ввиду под "динамическим созданием"?
См. Delegate.CreateDelegate().
...
C>Каждый обработчик возвращает int, комбайнер запоминает максимум. При значении больше 100 C>досрочно прекращается вызов сигналов.
Честно говоря, на мой взгляд, выглядит как совершенно непонятная каша. Можешь задачу словами описать?
Здравствуйте, vdimas, Вы писали:
V>О каком общем фоне речь? У кого хватает ошибок при многопоточном программировании? Шутку понял, но ты утрируешь.
У всех. Многопоточный код традиционно более глючный.
VD>>Еще раз. Не модифицируй переменные в анонимных методах и проблем никогда не возникнет.
V>Аналогично. Хотя, твое утрирование вышло за разумные рамки. Кто не должен модифицировать переменные? И нафига они тогда нужны?
Целая куча языков живут вообще без модификации переменных и ничего. Лучше что-то чем ничего. Определили переменную и ладно... Заморозили ее значение и используем... Замораживать можно при получении ссылки на метод.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Cyberax, Вы писали:
C>Релиза официального нет? Тогда свободны (а то я могу сказать, что TR1 и C>XTI (eXtended Type Information) для С++ давно уже доступны — для тех кто не жмурится).
Дай ссылку на место откуда они возможны, плиз.
C>А если в процессе обработки getData произойдет изменение списка C>слушателей? Так что пробуйте дальше.
Как говорил Альф "а если не сработает ваше земное притяжение?".
Хреново ты дотнет знашь. Не может измениться список. Списка слушателей нет. Есть список вызовов (реальных ссылок на пары метод/объект). Так вот этот список неизменяемый. При комбинировании делегатов или при создании нового просто пораждается новый делегат с новым списоком. 1:1 как в ФЯ. При этом никаких проблем с синхронизацией не может быть в принципе.
>> Что не сильно сложнее, но особого смысла не имеет.
C>Это только так кажется.
Что кажется и почему? Обоснуй, плиз.
C>Опять, же нужен рефлекшн. Если возможный набор методов известен на этапе компиляции, то делается элементарно и в С++.
Рефлекшен в С++ вроде как появится. А вот то что описанная мной динамика появлися я лично сильно сомневаюсь. Разубеди, плиз.
>> Это конечно тоже упирается в убогость рантайма С++, но если верить >> слухам о появлении в плюсах в каком-то виде рефлекшона, то такая >> возможность была бы очень востребована. Лично я очень часто использую >> делегаты именно как решение рантаймных проблем.
C>Это скорее всего можно будет сделать.
Ой сомневаюсь я...
C>Можно, но код будет не сегодня — некогда. Опишу пример словами: C>1. Есть сигнал и набор слушателей, слушатели разделяются на несколько C>уровней приоритета (слушатели должны вызываться в порядке убывания C>приоритета). C>2. Каждый обработчик может запретить вызов дальнейших обработчиков. C>3. Каждый обработчик возвращает целое число, после обработки всех C>сигналов я должен получить список возвращенных значений.
Не слишком сложно?
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>По-моему, речь шла о другом: поддерживают ли делегаты все те же неявные преобразования, что разрешены при вызовах функций в данном языке.
Дык в данном языке в C# неявное приведение int к short как раз и не разрешены.
ПК> Какие конкретно разрешены неявные преобразования в том или ином языке — разговор отдельный, к делегатам/сигналам не относящийся. Давай, чтоб не отвлекаться, сделаем так, чтоб усечения не было, но неявное преобразование осталось: ПК>
ПК>void fun1(int a)
ПК>{
ПК> cout << a << endl;
ПК>}
ПК>void fun2(long a)
ПК>{
ПК> cout << a << endl;
ПК>}
ПК>int main()
ПК>{
ПК> signal<void (int)> fun;
ПК> fun.connect(&fun1);
ПК> fun.connect(&fun2);
ПК> fun(10);
ПК>}
ПК>
ПК>Итак?..
Никак. Изменить размер памяти невозможно. Но переходник легко решает данную проблему. А вот подобная сущность сразу становится не компонентной, так как зависит от размеров типов конкретной функции и в рантайме с ней будут огромные проблемы.
В общем, веселые времена будут если в С++ таки введут рефлекшон, но не сделают полноценной ссылки на методы. Ну, да за то на наш форум по С++ будет процветать.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Так вот замыкание — это метод с контекстом. Выразить это можно как указатель на метод. Вот делегат и является таким указателем.
Замыкание — действительно метод с контекстом, а делегат — указатель на метод. Но вот выразить "метод с контекстом" как "указатель на метод" не получится. Поэтому делегаты — не замыкания.
VladD2,
> ПК> Меняется: копирование становится скрытым, неочевидным. > > А в С++ что-то было очевидным и не скрытым?
Время жизни объектов. Если последовать твоему предложению, и начать неявно копировать контекст, время жизни объектов начнет непредсказуемо изменяться только из-за того, что их кто-то решил их использовать в анонимной функции.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, WFrag, Вы писали: WF>Насколько я помню, в Дельфи вроде бы можно функции одна в другую вкладывать.
Можно WF>Можно ли сделать так, чтобы две вложенные функции (например, InnerA и InnerB) общались через локальную переменную во "внешней" функции.
Можно. WF>Псевдо-код (Дельфи плохо знаю). WF>Так вот. Если эти A и B вернуть наружу Outer, то вызывая их по-очереди, что получим?
Ничего. Взять адрес вложенной функции нельзя. У нее нет собственного фрейма стека.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Время жизни объектов. Если последовать твоему предложению, и начать неявно копировать контекст, время жизни объектов начнет непредсказуемо изменяться только из-за того, что их кто-то решил их использовать в анонимной функции.
Ты ничего не путашь? В С++ никогда наличие ссылок не определяло время жизни. Все будет как и раньше. Сылки на мертвые объекты и ручное управление жизнью, тобы это происходило по реже.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, WFrag, Вы писали: WF>>Ага. Понятно. То есть замыканий все-таки нет. Вложенные функции получается и не функции в общем-то. S>Да. Все, что можно замкнуть в Delphi — это ссылку на экземпляр объекта, на котором выполняется данный метод.
"Всего то" К этому всему-то приципили виртуальные конструкторы/фабрики, примитивнийший рефлекшон и получилась самодостаточная среда для компонентного программирования не требующая костылей вроде КОМ-а.
Плюсам бы такое "всего то". Ну, или Дельфям шаблоны с операторами.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VladD2 wrote:
> E>Правда? Я вот надеюсь, что boost::bind станет частью языка, тогда > это будет такой же стандартный механизм, как делегаты, а не заплатка. > Не беспокойся — не станет. Я тут прочел твою ссылку на очередное > откровение Страуструпа и понял, что основные вещи он уеж решил (ну, > классы есть же?) а мелочи вроде делегатов или процедурных типов он > делать не желает.
Желает. Сейчас обсуждаются function types, они почти 100%но будут в
Стандарте.
> Это мелкие частности. Ну, что поделать если человек настолко > образован, что ему плевать на целую парадигму функционального > программирования? В общем, орлам вроде Степанова и дальше прийдется > извращаться, чтобы написать примитивную фичу вроде boost::bind. Причем > компилироваться это будет часами. В общем, маразм крепчал...
1. Далеко не все решает один Страуструп.
2. Как раз ФП будет уделено больше внимания (до введения в Стандарт
лямбда-выражений).
Здравствуйте, Cyberax, Вы писали:
C>Желает. Сейчас обсуждаются function types, они почти 100%но будут в C>Стандарте.
Может где-то он и обсуждается. Но хрена два "оно" будет. Тут eao197 дал ссылку на поток мысли Страуструпа перепечатанный CppUJ так из его слов ясно понятно что "все эти функциональные типы — это частности и мелочи. Кульные патцаны ведь народу классы дают. Это куда руче." Бред в общем. Так что если Страус будет конечной инстанцией то шиш с маслом будет вместо делегатов в С++.
C>1. Далеко не все решает один Страуструп.
Будем надеяться, что это так. Иначе хана С++. Убъет его он.
C>2. Как раз ФП будет уделено больше внимания (до введения в Стандарт C>лямбда-выражений).
По словам Страуструпа все немного не так. Ну, не нравится ему простые решения.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VladD2,
> C> Сейчас обсуждаются function types, они почти 100%но будут в Стандарте.
> Может где-то он и обсуждается. Но хрена два "оно" будет. Тут eao197 дал ссылку на поток мысли Страуструпа перепечатанный CppUJ так из его слов ясно понятно что "все эти функциональные типы — это частности и мелочи. Кульные патцаны ведь народу классы дают. Это куда руче." Бред в общем. Так что если Страус будет конечной инстанцией то шиш с маслом будет вместо делегатов в С++.
Я так ты ведешь речь об этом высказывании:
People comparing languages using lists love such features. The snag is that the problems we face are essentially infinite, so we need an infinity of such specialized features. Examples are Pascal procedure parameters and C# delegates. The alternative traditionally offered by C++ (and before that by K&R C) is to provide very general features from which good programmers can construct solutions to a wide variety of problems. Examples are pointers and classes.
Теперь объясни, как именно это исключает введение стандартных классов, представляющих function type?
> C>2. Как раз ФП будет уделено больше внимания (до введения в Стандарт лямбда-выражений). > > По словам Страуструпа все немного не так.
Можно конкретную цитату?
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Я так ты ведешь речь об этом высказывании: ПК>
People comparing languages using lists love such features. The snag is that the problems we face are essentially infinite, so we need an infinity of such specialized features. Examples are Pascal procedure parameters and C# delegates. The alternative traditionally offered by C++ (and before that by K&R C) is to provide very general features from which good programmers can construct solutions to a wide variety of problems. Examples are pointers and classes.
Об этом, об этом.
ПК>Теперь объясни, как именно это исключает введение стандартных классов, представляющих function type?
Стандарные классы без изменения языка — это маразм. Зачем объходить проблемы лепя горы кода и получая совершенно неудобоваримый результат вместо того чтобы встроить в язык саму собой напрашивающуюся вещь?
ПК>Можно конкретную цитату?
Ты ее привел сам.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, VladD2, Вы писали:
VD>>Стандарные классы без изменения языка — это маразм. Зачем объходить проблемы лепя горы кода и получая совершенно неудобоваримый результат вместо того чтобы встроить в язык саму собой напрашивающуюся вещь?
V>Странное рассуждение. В C# весь reflection доступен так же в виде модели экземпляров классов-дескрипторов. Ничего такого в язык не вставлено.
В C# есть делегаты и анонимные методы. Они полностью поддерживаются компилятором в следствии чего их очень просто и удобно использовать. Для компилятора такая поддержка ничего не стоит. А вот для программиста она дает практически молниеносную компиляцию.
V> Если "узаконить" часть буста (типа как std::type_info), то зачастую, достаточно будет лишь небольшой поддержки компилятором без значительных изменений языка.
Чтобы вставить делегаты (клозюры, функциональный тип и т.п.) не нужна какая-то сверхестественная модификация языка. Нужно ввести новый тип указателя. Синтаксис будет практически таким же как при работе с указателями на глобальные функции. Ну, и нужно разрешить объявлять анонимные функции. Это очень небольшие изменения. И просто вселенской глупостью будет если комитет откажется от этого и узаконит бустовскую эмуляцию.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, vdimas, Вы писали:
VD>>Чтобы вставить делегаты (клозюры, функциональный тип и т.п.) не нужна какая-то сверхестественная модификация языка. Нужно ввести новый тип указателя. Синтаксис будет практически таким же как при работе с указателями на глобальные функции. Ну, и нужно разрешить объявлять анонимные функции. Это очень небольшие изменения. И просто вселенской глупостью будет если комитет откажется от этого и узаконит бустовскую эмуляцию.
V>Ну и как ты себе представляешь продление времени жизни локальных переменных, используемых анонимной ф-ий.
Я в даном случае говорил только о "делегатах/замыканиях/функциональных типах" (далее — делегаты). Ссылаться они могут на обычные функции. Было бы конечно здорово если бы ввели анонимные методы и еще лучше если бы в них сделали возможность ссылаться на локальный контекст, но это все же не боле чем улучшение. А сами делегаты все же важнее. И их то как раз реализовать ничего не стоит. Можно считать, что это поправка старой ошибки.
V>Я прекрасно знаю, как это сделано в C# 2.0, тем не менее, на мой взгляд, это тааааакие грабли, при мультипоточном использовании подобных анонимных делегатов. Абсолютно неочевидные и гнусные грабли.
Мне кажется ты преувеличиваешь. Проблема многопоточного программирования — это отдельная проблема. Она существует без каких бы то нибыло дополнений. И единственный простой ее обход — это постоянно порождать копию данных (в общем использовать функциональный стиль). И тут как раз анонимные методы очень даже неплохо могут себя показать если не менять эти переменные внутри анонимных методов.
Ну, а модификация переменных... Дык это общая проблема императивных языков. Так что если мы говорим о таком на сквозь императивном языке как С++, то рассуждать о потенциальной грабельности модификации переменных в многопоточных программах просто смешно.
ЗЫ
Не оверквоть, плиз.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Еще раз ошибаешся. Не контекст вызова, а контекст функции.
Да, я оговорился. Не контекст вызова, а контекст в точке создания.
VD>Проблемы в С++ несомненно будут. Но не технические, а проблемы с тараканами в мозгах его авторов.
Нет, я хочу сказать что проблема довольно серьезная и вряд ли вообще решаема без серьезных изменений (например, GC). Поэтому твои лихие слова о тараканах в голове мне и не нравятся. Не так все просто, как мне кажется.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Это делается легко и с boost::function и аналогами.
Мало ли что где делается. Сущьности не равноценны.
VD>> Потом это полноценный компонентный тип. Его можно передать в другие компоненты, по сети и т.п. Его можно создать в рантайме.
ПК>Это уже ограничения среды исполнения: либо она поддерживает подобные вещи, либо нет. В C++ подобной поддержки (по крайней мере, в готовом виде) нет в принципе.
Тем хуже для С++. Но проблема в том, что этой поддержки нет и чужими стараньями. И скорее всего никогда не появится. КОМ и Корба так и будут пользоваться своими велосипедами.
ПК> От того, что boost::function стал бы, как ты предлагаешь, встроенным типом, эти аспекты бы ни на капельку не изменились бы.
Ну почему же? Думаю, разработчики КОМ-а и Корбы нашли бы способ использовать встроенный тип.
VD>> Они даже могут быть обобщенными. Ну, что-то вроде: VD>>
VD>>delegate bool Predicate<T>(T t);
VD>>
ПК>Это и для boost::function верно.
Возможно. Продемонстрируй, плиз, код.
VD>>Ну, и на его компиляцию практически не тратится времени.
ПК>Намного более общим подходом является решение проблем скорости компиляции (введение поддержки модулей и т.д.), нежели введение в язык "хэков" для поддержки всевозможных популярных компонентов: boost::function, std::vector, std::list и т.п.
Модули модулями, но шаблоны есть шаблоны. На их обработку будет тратиться намного больше времени чем на обработку встренного примитива.
К тому же при испльзовании шаблонов в МС++ они приводят к нехилому разбуханию метаинформации, что тоже не здорово.
В общем, я не вижу смысла решать проблемы метапрограммированием там где просто напрашивается введение примитива в язык.
VD>>В общем, дело не в виде который примет сам указатель. В том же шарпе делегат это тоже класс. Дело в поддежке со стороны компилятора и во внутренней реализации. Если это дело будет выглядеть как boost::function но при этом внутри появится хак, то многие проблемы исчезнут. Но куда логичнее просто ввести новый тип указателя и уже на его базе делать остальные решения.
ПК>В общем, дальше можно не продолжать: аргументация подобного уровня мне неинтересна.
Аргументы соврешенно нормальные. Просто вести беседу с людьми которые принципиально уверены в своей правоте бессмысленно. Они всегда находят проблему в собеседнике. Так поступил и ты.
Ты не хочешь воспринимать мои аргументы и априори (без какой либо аргументации) объявляешь их ничтожными.
Счасливо оставаться со своим мнением. Оно не поколибимо.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, WFrag, Вы писали:
VD>>Еще раз ошибаешся. Не контекст вызова, а контекст функции.
WF>Да, я оговорился. Не контекст вызова, а контекст в точке создания.
Создания чего? Метода? Да не сомненно.
VD>>Проблемы в С++ несомненно будут. Но не технические, а проблемы с тараканами в мозгах его авторов.
WF>Нет, я хочу сказать что проблема довольно серьезная и вряд ли вообще решаема без серьезных изменений (например, GC). Поэтому твои лихие слова о тараканах в голове мне и не нравятся. Не так все просто, как мне кажется.
Ты очередной раз умудрился не понять, что я говорю. Еще раз. Closur != анонимным методам (или если угодно, ламбдам). Closur == делегат. И на этом уровне проблем вообще нет. Почитай хотя бы документацию по Дельфи.
Ну, а что до анонимных методов, то опять же можно не давать модифицировать контекст (как это делается в функциональных языках). Тоже решение. В общем, решений может быть масса. Было бы желание их искать.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, vdimas, Вы писали:
V>Речь о другом. Есть некие устоявшиеся постулаты при работе с мультипоточными программами. Например — локальные переменные доступны лишь контексту текущего потока (т.к. стек — это приватный элемент потока). Далее, мы вводим анонимный делегат, который в начале не использует некие локальные переменные. После очередной доработки кто-то незаметно решил попользовать локальную переменную в анонимном коде делегата. И эта переменная незаметно перестала быть стековой. Собственно, в этом суть упомянутых граблей.
Повторюсь. Мне кажется это напрасные страхи. Вероятность проблем здесь не ислючена, но она очень мала. Между тем, при многопоточном программировании ошибок и без того хватает. Так что на общем фоне проблемы не будет.
За то в однопоточном коде это даст много приемуществ.
V>Если уточнить, что речь о стековых переменных, то становится уже не смешно, а чуточку страшно. Локальный контекст — это вообще единственная точка опоры при многопоточном программировании.
Еще раз. Не модифицируй переменные в анонимных методах и проблем никогда не возникнет.
В общем, тут скорее нужно бы обсудить введение в Шарп readonly для локальных переменных. Тогда и проблем не будет.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Require exact type matches between a delegate and what it is calling.
Это проблема не дотнета а Шарпа 1.х. данная проблема устранена в C# 2.0.
Only return the result of the last target called, with no option for customization.
Вообще не проблема. Используй массив делегатов.
Must call a method with this already bound.
А это уже приемущество записали в проблему. К тому же, в дотнете нет никаких проблем конструировать делегаты на лету. Так что this можно прикрутить какой угодно.
А вот про проблемы бинда почему то ни звука. А их не мало. Медленная компиляция, невозможность анализа signal-а как единой сущьности невозможность динамического создания сигналов и т.п.
Кстати, забавно было бы сравнить код на делегатах и сигналах.
C>Лично мне, например, сигналы нравятся намного больше С# делегатов (при C>использовании делегатов как сигналов).
А лично мне наоборот. Только при использовании делегатов как делегатов.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Создания чего? Метода? Да не сомненно.
В точке создания замыкания, там где new delegate() {...}. Там захватывается текущий контекст — биндинги переменных.
VD>Ты очередной раз умудрился не понять, что я говорю. Еще раз. Closur != анонимным методам (или если угодно, ламбдам). Closur == делегат.
Не понял, к чему это? Я про возможность.
VD>И на этом уровне проблем вообще нет. Почитай хотя бы документацию по Дельфи.
Что я там должен найти?
VD>Ну, а что до анонимных методов, то опять же можно не давать модифицировать контекст (как это делается в функциональных языках). Тоже решение. В общем, решений может быть масса. Было бы желание их искать.
Дык проблема-то не только в модификации! Проблема в том, что локальная переменная просто перестает существовать при выходе из метода, а замыкание все еще может быть. И в наивной реализации, если мы его вызовем, то оно обратится к несуществующей переменной и попортит стек.
Здравствуйте, WFrag, Вы писали:
WF>Дык проблема-то не только в модификации! Проблема в том, что локальная переменная просто перестает существовать при выходе из метода, а замыкание все еще может быть. И в наивной реализации, если мы его вызовем, то оно обратится к несуществующей переменной и попортит стек.
Что-то я протупил. Действительно, в этом случае можно просто полностью скопировать контекст. Правда, остается другая проблема. Если захваченная локальная переменная — указатель (немодифицируемый), указывающий на другую локальную переменную. Указатель скопируется, но то, на что он указывал — помрет.
Здравствуйте, VladD2, Вы писали:
VD>Повторюсь. Мне кажется это напрасные страхи. Вероятность проблем здесь не ислючена, но она очень мала. Между тем, при многопоточном программировании ошибок и без того хватает. Так что на общем фоне проблемы не будет.
О каком общем фоне речь? У кого хватает ошибок при многопоточном программировании? Шутку понял, но ты утрируешь.
VD>Еще раз. Не модифицируй переменные в анонимных методах и проблем никогда не возникнет.
Аналогично. Хотя, твое утрирование вышло за разумные рамки. Кто не должен модифицировать переменные? И нафига они тогда нужны?
Здравствуйте, Cyberax, Вы писали:
>> C>данная проблема устранена в C# 2.0.
C>Которого еще нет в природе (до ноября, кажется?).
Который давно доступен для использоания. А нет его только для тех кто сильно жмурится.
C>Угу, и самому делать мультикаст. Спасибо, благодарю.
Что там делать то?
GetData getDataMulticast = f1 + (GetData)f2 + f3;
int sum = 0;
foreach (GetData getData in getDataMulticast.GetInvocationList())
sum += getData();
или так:
delegate int GetData();
...
GetData[] getDataArray = new GetData[] { f1, f2, f3 };
int sum = 0;
foreach (GetData getData in getDataArray)
sum += getData();
Что не сильно сложнее, но особого смысла не имеет.
C>Компиляция — это вообще проблема С++.
Ага. Как и все остальные проблемы.
C> А насчет анализа — когда он будет C>в С++, то будут методы кастомизировать его, чтобы представлять сложные C>объекты, как "единую сущность".
Боюсь, будет очередной уродец. Ну, да через три года поглядим.
C>А что вы имеете ввиду под "динамическим созданием"?
Возможность создать экземлпяр делегата в рантайме и привезать его к произвольному методу не извесному на момент компиляции. Это конечно тоже упирается в убогость рантайма С++, но если верить слухам о появлении в плюсах в каком-то виде рефлекшона, то такая возможность была бы очень востребована. Лично я очень часто использую делегаты именно как решение рантаймных проблем.
>> Кстати, забавно было бы сравнить код на делегатах и сигналах.
C>С мультикастом? Вполне: C>
Здравствуйте, VladD2, Вы писали:
VD>Возможность создать экземлпяр делегата в рантайме и привезать его к произвольному методу не извесному на момент компиляции. Это конечно тоже упирается в убогость рантайма С++, но если верить слухам о появлении в плюсах в каком-то виде рефлекшона, то такая возможность была бы очень востребована. Лично я очень часто использую делегаты именно как решение рантаймных проблем.
А откуда слухи о появлении в C++ рефлекшена?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
eao197 wrote:
> VD>Возможность создать экземлпяр делегата в рантайме и привезать его к > произвольному методу не извесному на момент компиляции. Это конечно > тоже упирается в убогость рантайма С++, но если верить слухам о > появлении в плюсах в каком-то виде рефлекшона, то такая возможность > была бы очень востребована. Лично я очень часто использую делегаты > именно как решение рантаймных проблем. > А откуда слухи о появлении в C++ рефлекшена?
Это не слухи, Страуструп усиленно продвигает XTI еще с 99 года.
Здравствуйте, alexeiz, Вы писали:
A>Не трудно продемонстрировать примером? Чтобы вроде этого вышло: A>
A>void fun1(int a)
A>{
A> cout << a << endl;
A>}
A>void fun2(short a)
A>{
A> cout << a << endl;
A>}
A>int main()
A>{
A> signal<void (int)> fun;
A> fun.connect(&fun1);
A> fun.connect(&fun2);
A> fun(10);
A>}
A>
Это пример нарушения работы с типами. Идет усечение данных без явного приведения типов (неговоря уже о контроле переполения). Так что печально, что такое вообще можно сделать.
Аналогичный код на шарпе написать можно, но только с явным приведением типов и как следствие с введением периходника:
delegate void Test(int a);
static void Main(string[] args)
{
Test fun = fun1 + new Test(delegate(int a) { fun2((short)a); });
fun(10);
}
static void fun1(int a)
{
Console.WriteLine("void fun1(int a); a = " + a);
}
static void fun2(short a)
{
Console.WriteLine("void fun1(int a); a = " + a);
}
Что же касается коваринтности, то она есть для типов один из которых унаследован от дугого. Назвается коваринтность. Выглядит это так:
class A { }
class B : A { }
class Program
{
delegate void Test(B b);
static void Main(string[] args)
{
Test fun = fun1 + (Test)fun2;
fun(new B());
}
static void fun1(A a)
{
Console.WriteLine("void fun1(A a); a is " + a.GetType().Name);
}
static void fun2(B b)
{
Console.WriteLine("void fun1(B b); b is " + b.GetType().Name);
}
}
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>В этом как раз и есть разница, о которой говорил Страуструп: в C++ не видят смысла вводить примитив в язык, если можно ввести возможность, позволяющую сделать ту же задачу с помощью создания библиотеки.
Если бы это быал билиотека создающее нечто большее из примитивов, то я бы был целиком согласен. Но эта библиотека — хак. Это обход проблемы созданной в языке — заплатка. И чем узаконивать заплатки, лучше исправить ошибку введя более общий тип указателя на метод.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, WFrag, Вы писали:
WF>В точке создания замыкания, там где new delegate() {...}. Там захватывается текущий контекст — биндинги переменных.
Нет никаких "точек зрения замыкания". Анонимный метод имеет свой контекст. В него попадают локальные переменные внешнего метода. Обычный метод тоже имеет свой контекст, но в него не попадают локальные переменные.
Так вот замыкание — это метод с контекстом. Выразить это можно как указатель на метод. Вот делегат и является таким указателем. А анонимный метод всего лишь частный случай метода. Не более того. Так что ты путаешь понятие анонимного метода и замыкания. Это не одно и тоже. Анонимный метод может быть использован в качестве замыкания, но замыкание можно сделать и без анонимного метода.
В общем, замыкание плохой термин. Он путает. По этому я и пользуюсь словом делегат.
VD>>Ты очередной раз умудрился не понять, что я говорю. Еще раз. Closur != анонимным методам (или если угодно, ламбдам). Closur == делегат.
WF>Не понял, к чему это?
У тебя каша в голове. Прочти еще раз сообщение ссылку на которое я привел.
WF>Я про возможность.
VD>>И на этом уровне проблем вообще нет. Почитай хотя бы документацию по Дельфи.
WF>Что я там должен найти?
Описание Closur которое применяется в дельфи уже 10 лет. Еще можешь поискать предложение Борланда по расширению С++ вводящему в С++ те самые замыкания.
WF>Дык проблема-то не только в модификации! Проблема в том, что локальная переменная просто перестает существовать при выходе из метода,
Если переменная не модифицируется, то достаточно скопировать (запомнить) ее значение. Все ФЯ так и поступают. Даже при линивых вычислениях (когда переменная вычисляется непосредственно перед применением) ее копирую (создают два экземпляра). При этом останется возможность передать информацию в метод, но гибкости будет чуть меньше. В итоге получится простое решение.
WF> а замыкание все еще может быть.
Блин, не замыкание, а анонимный метод. Он и будет со своей копией данных полученной при его создании.
WF> И в наивной реализации, если мы его вызовем, то оно обратится к несуществующей переменной и попортит стек.
Он обратится к копии данных.
А вообще очень смешно слышать про заботу о С++-программисте. "Ой не дай бог он что-то не то сделает!" И это при том, что в плюсах без проблем можно поместить в указатель адрес переменной созданной в стеке метода и возратить его во вне метода.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, WFrag, Вы писали:
WF>Что-то я протупил. Действительно, в этом случае можно просто полностью скопировать контекст. Правда, остается другая проблема. Если захваченная локальная переменная — указатель (немодифицируемый), указывающий на другую локальную переменную. Указатель скопируется, но то, на что он указывал — помрет.
Что значит помрет? Метод получит копию. Единственная проблема заключается в том, что это будет копия на момент первого обращения к методу. Конечно это противоречит идее импиративного языка и снижает возможности, но за то просто в реализации и не создает побочных эффектов.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VladD2,
> A>Не трудно продемонстрировать примером? Чтобы вроде этого вышло: > A>
> A>void fun1(int a)
> A>{
> A> cout << a << endl;
> A>}
>
> A>void fun2(short a)
> A>{
> A> cout << a << endl;
> A>}
>
> A>int main()
> A>{
> A> signal<void (int)> fun;
> A> fun.connect(&fun1);
> A> fun.connect(&fun2);
> A> fun(10);
> A>}
> A>
> > Это пример нарушения работы с типами. Идет усечение данных без явного приведения типов (неговоря уже о контроле переполения). Так что печально, что такое вообще можно сделать.
По-моему, речь шла о другом: поддерживают ли делегаты все те же неявные преобразования, что разрешены при вызовах функций в данном языке. Какие конкретно разрешены неявные преобразования в том или ином языке — разговор отдельный, к делегатам/сигналам не относящийся. Давай, чтоб не отвлекаться, сделаем так, чтоб усечения не было, но неявное преобразование осталось:
void fun1(int a)
{
cout << a << endl;
}
void fun2(long a)
{
cout << a << endl;
}
int main()
{
signal<void (int)> fun;
fun.connect(&fun1);
fun.connect(&fun2);
fun(10);
}
Итак?..
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
VladD2,
> WF>Что-то я протупил. Действительно, в этом случае можно просто полностью скопировать контекст. Правда, остается другая проблема. Если захваченная локальная переменная — указатель (немодифицируемый), указывающий на другую локальную переменную. Указатель скопируется, но то, на что он указывал — помрет.
> Что значит помрет? Метод получит копию.
Копию указателя. А то, на что данный указатель указывает, — вполне может помереть.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
VD>Это пример нарушения работы с типами. Идет усечение данных без явного приведения типов (неговоря уже о контроле переполения). Так что печально, что такое вообще можно сделать.
Да, тут я наврал. Со свичом /Wall, наверное, можно было выявить. Но фишка не в этом. Я мог бы использовать long вместо short. Фишка в том, что boost::signal не требует точного соответствия типов параметров. Если существует приведение типов к нужным, оно будет задействовано. Именно это и имелось ввиду в сравнении boost::signal с .NET delegates.
А ковариантные возвращаемые значения — это basics. Странно, что только в v2 они стали поддерживаться delegate'ами.
VladD2,
> ПК>По-моему, речь шла о другом: поддерживают ли делегаты все те же неявные преобразования, что разрешены при вызовах функций в данном языке. > > Дык в данном языке в C# неявное приведение int к short как раз и не разрешены.
Тогда к чему эти возгласы о нарушении работы с типами? В системе типов C++ (и, как ты утверждаешь, C#) типы int и short совместимы...
> ПК>
> ПК>Итак?..
> Никак. Изменить размер памяти невозможно. Но переходник легко решает данную проблему.
Размер памяти здесь совершенно ни при чем: boost::signal порождает именно такие переходники, как ты описываешь (если я правильно понимаю, о чем ты говоришь), автоматически, в точке привязки функции к сигналу.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
VladD2,
> ПК> Копию указателя. А то, на что данный указатель указывает, — вполне может помереть.
> А что в С++ когда-то было по другому? В данном случае ничего не меняется.
Меняется: копирование становится скрытым, неочевидным.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Cyberax, Вы писали:
C>eao197 wrote:
>>>> А откуда слухи о появлении в C++ рефлекшена? >> C>Это не слухи, Страуструп усиленно продвигает XTI еще с 99 года. >> А точной ссылкой на описание XTI не поделишься?
C>Вот презентация от Страуструпа: C>http://lcgapp.cern.ch/project/architecture/XTI_accu.pdf
C>Где-то я видел ссылку на более новую версию, но вот где именно — точно C>не вспомню.
C>-- C>С уважением, C> Alex Besogonov (alexy@izh.com)
Очень интересно. И, похоже, реализуемо заточкой gcc.
Здравствуйте, VladD2, Вы писали:
WF>>В точке создания замыкания, там где new delegate() {...}. Там захватывается текущий контекст — биндинги переменных.
VD>Нет никаких "точек зрения замыкания". Анонимный метод имеет свой контекст. В него попадают локальные переменные внешнего метода. Обычный метод тоже имеет свой контекст, но в него не попадают локальные переменные.
Точка создания. Контекст — штука динамическая, при одном вызове метода create переменная val (имя val) связана (т.н биндинг) с одной областью хранения (некоторое место в стеке), при втором вызове — с другой. Вот эти биндинги и запоминаются. В общем, забей.
Так вот, то, что мы создаем — это и есть замыкание. По определению. Функция (некоторый код со свободными переменными) + снимок лексического окружения (видимые переменные) в момент создания замыкания (их текущие биндинги).
Кстати, цитата из Википедии:
[quote]
Support for closures is introduced in version 2.0 of C#. In C#, they are called "anonymous methods".
[/quote]
VD>В общем, замыкание плохой термин. Он путает. По этому я и пользуюсь словом делегат.
Отлично, VladD2!! Пять баллов!
WF>> а замыкание все еще может быть.
VD>Блин, не замыкание, а анонимный метод. Он и будет со своей копией данных полученной при его создании.
Нет, именно сущность под названием "замыкание". Функция + контекст = замыкание.
Здравствуйте, WFrag, Вы писали:
WF>Кстати, цитата из Википедии: WF>[quote] WF>Support for closures is introduced in version 2.0 of C#. In C#, they are called "anonymous methods". WF>[/quote]
Замечу, что я не согласен с этим куском Если что, я вообще нигде не говорил, что анонимный метод = замыкание. Анонимный метод — "статическая" сущность программы (т.е существует в коде), замыкание — "динамическая" (т.е возникает только при выполнении программы, в коде замыканий нет, есть только код порождения замыкания).
Анонимные методы были приведены в пример исключительно потому что они гораздо интереснее, чем "внешние" методы (не вложенные в другие методы). Подошли бы и просто вложенные методы, но ведь их нет, не так ли?
VD>>В общем, замыкание плохой термин. Он путает. По этому я и пользуюсь словом делегат.
WF>Отлично, VladD2!! Пять баллов!
Если непонятна ирония, это я к тому, что не хочу пользоваться ad-hoc определениями. Есть устоявшееся понятие, если оно тебя путает, это не значит, что надо его заменять сиюминутными "делегатами".
Здравствуйте, VladD2, Вы писали:
VD>>>И на этом уровне проблем вообще нет. Почитай хотя бы документацию по Дельфи.
Что-то не нашел я там замыканий. Ссылки на функции, даже ссылки на методы конкретного объекта есть, а вот замыканий не вижу.
Насколько я помню, в Дельфи вроде бы можно функции одна в другую вкладывать. Можно ли сделать так, чтобы две вложенные функции (например, InnerA и InnerB) общались через локальную переменную во "внешней" функции.
Псевдо-код (Дельфи плохо знаю).
function Outer() : ??? {некий тип};
var
val : Integer;
A: function(): Integer;
B: function(): Integer;
begin
val := 0;
function InnerA
begin
inc(val);
InnerA := val
end;
function InnerB
begin
dec(val);
InnerB := val
end;
A := InnerA;
B := InnerB;
{ Как-то возвращаем A и B наружу }end;
Так вот. Если эти A и B вернуть наружу Outer, то вызывая их по-очереди, что получим?
Например, каков будет результат последовательности:
A();
A();
s := B();
s должно быть 1 (два раза увеличили val, один раз уменьшили).
Здравствуйте, Трурль, Вы писали:
Т>Замыкание — действительно метод с контекстом, а делегат — указатель на метод. Но вот выразить "метод с контекстом" как "указатель на метод" не получится. Поэтому делегаты — не замыкания.
В .NET 2.0 ссылка типа "делегат" может ссылаться на замыкание.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>VladD2,
>> ПК>По-моему, речь шла о другом: поддерживают ли делегаты все те же неявные преобразования, что разрешены при вызовах функций в данном языке.
Согласен, язык кривоват, но пример то предлагалось создать на Шарпе.
ПК>Тогда к чему эти возгласы о нарушении работы с типами? В системе типов C++ (и, как ты утверждаешь, C#) типы int и short совместимы...
А нарушение оно не в С++. Оно по жизни.
ПК>Размер памяти здесь совершенно ни при чем: boost::signal порождает именно такие переходники, как ты описываешь (если я правильно понимаю, о чем ты говоришь), автоматически, в точке привязки функции к сигналу.
Возможно. Мне казалось, что он просто генерирует специализации под конкретные типы.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, WFrag, Вы писали:
WF>Точка создания. Контекст — штука динамическая, при одном вызове метода create переменная val (имя val) связана (т.н биндинг) с одной областью хранения (некоторое место в стеке), при втором вызове — с другой. Вот эти биндинги и запоминаются. В общем, забей.
Продемонстрируй мне, плиз, на любом языке (на шпрпе так вообще замечательно бедет) как меняется контекст от вызова.
WF>Кстати, цитата из Википедии: WF>[quote] WF>Support for closures is introduced in version 2.0 of C#. In C#, they are called "anonymous methods". WF>[/quote]
Там тоже кто хочет тот и пишет.
WF>Нет, именно сущность под названием "замыкание". Функция + контекст = замыкание.
Мне этот спор надоел. Думаю ты понял о чем я говорю.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Трурль, Вы писали:
Т>Здравствуйте, VladD2, Вы писали:
VD>>Так вот замыкание — это метод с контекстом. Выразить это можно как указатель на метод. Вот делегат и является таким указателем.
Т>Замыкание — действительно метод с контекстом, а делегат — указатель на метод. Но вот выразить "метод с контекстом" как "указатель на метод" не получится. Поэтому делегаты — не замыкания.
В каком-то смысле согласен. Делегат и клосюр в дельфи — это конечно указатель. Именно по этому мне не очень нравится применение этого термина. Экземпляр функционального типа или делегата будет по понятнее. Ну, и метод + анонимный метод или функция и лямбда для описания самих функций тоже.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, WFrag, Вы писали:
WF>Для начала определю, что контекст — это множество пар <имя, область хранения>, т.е множество биндингов. Наверное, это следовало бы сделать сразу.
Нет. Для начала мы определимся, что контекст — это набор перепенных доступной и некоторой точки.
Все остальное соотвественно смысла не имеет.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, WFrag, Вы писали: WF>>Насколько я помню, в Дельфи вроде бы можно функции одна в другую вкладывать. S>Можно WF>>Можно ли сделать так, чтобы две вложенные функции (например, InnerA и InnerB) общались через локальную переменную во "внешней" функции. S>Можно. WF>>Псевдо-код (Дельфи плохо знаю). WF>>Так вот. Если эти A и B вернуть наружу Outer, то вызывая их по-очереди, что получим? S>Ничего. Взять адрес вложенной функции нельзя. У нее нет собственного фрейма стека.
Ага. Понятно. То есть замыканий все-таки нет. Вложенные функции получается и не функции в общем-то.
Здравствуйте, Павел Кузнецов, Вы писали:
>> А в С++ что-то было очевидным и не скрытым?
ПК>Время жизни объектов. Если последовать твоему предложению, и начать неявно копировать контекст, время жизни объектов начнет непредсказуемо изменяться только из-за того, что их кто-то решил их использовать в анонимной функции.
Да уж... как всё запущено
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Если нам не помогут, то мы тоже никого не пощадим.
IT,
> ПК> Время жизни объектов. Если последовать твоему предложению, и начать неявно копировать контекст, время жизни объектов начнет непредсказуемо изменяться только из-за того, что их кто-то решил их использовать в анонимной функции.
> Да уж... как всё запущено
Если время вызова деструктора существенно, это может иметь весьма разрушительные последствия, еще и трудно обнаружимые. Представь, что вызов Dispose() вдруг начнет происходить не там, где кончается блок using, а в каком-то другом месте. При этом для того, чтоб это произошло достаточно просто сослаться на данный объект где-то в одном из блоков внутри using...
Впрочем, не все так страшно, если ввести специальный синтаксис для копирующих ссылок на контекст, чтоб в точке использования переменной из окружающего блока было видно, что она будет скопирована.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Впрочем, не все так страшно, если ввести специальный синтаксис для копирующих ссылок на контекст, чтоб в точке использования переменной из окружающего блока было видно, что она будет скопирована.
А зачем вообще копировать что-то в контекст? Чем ссылки не устраивают?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Если нам не помогут, то мы тоже никого не пощадим.
IT,
> ПК>Впрочем, не все так страшно, если ввести специальный синтаксис для копирующих ссылок на контекст, чтоб в точке использования переменной из окружающего блока было видно, что она будет скопирована. > > А зачем вообще копировать что-то в контекст? Чем ссылки не устраивают?
Копирование предложил Влад в качестве решения другой проблемы, проблемы выхода контекста из области видимости < http://rsdn.ru/forum/?mid=1241014
>. Будет происходить, например, если где-то запомнить или вернуть из функции делегат, проинициализированный анонимной функцией, использующей локальные переменные "родительской" функции. Т.е., если контекст в замыкание не копировать, а только ссылаться на него, он может "умереть" до конца жизни замыкания, если копировать — появляются проблемы с неявным копированием, временем жизни и т.п.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Копирование предложил Влад в качестве решения другой проблемы, проблемы выхода контекста из области видимости < http://rsdn.ru/forum/?mid=1241014
>. Будет происходить, например, если где-то запомнить или вернуть из функции делегат, проинициализированный анонимной функцией, использующей локальные переменные "родительской" функции. Т.е., если контекст в замыкание не копировать, а только ссылаться на него, он может "умереть" до конца жизни замыкания, если копировать — появляются проблемы с неявным копированием, временем жизни и т.п.
Это таже проблема что и передача в функцию локальной переменной по ссылке. С ней бесполезно бороться.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Если нам не помогут, то мы тоже никого не пощадим.
VladD2,
> ПК> Время жизни объектов. Если последовать твоему предложению, и начать неявно копировать контекст, время жизни объектов начнет непредсказуемо изменяться только из-за того, что их кто-то решил их использовать в анонимной функции.
> Ты ничего не путашь? В С++ никогда наличие ссылок не определяло время жизни. Все будет как и раньше. Сылки на мертвые объекты и ручное управление жизнью, тобы это происходило по реже.
1) Наличие ссылок в определенных случаях влияет на время жизни (привязка rvalue к константным ссылкам).
2) Ты предложил копировать контекст: "Что значит помрет? Метод получит копию."
Здравствуйте, WFrag, Вы писали: WF>Ага. Понятно. То есть замыканий все-таки нет. Вложенные функции получается и не функции в общем-то.
Да. Все, что можно замкнуть в Delphi — это ссылку на экземпляр объекта, на котором выполняется данный метод.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, VladD2, Вы писали: VD>"Всего то" К этому всему-то приципили виртуальные конструкторы/фабрики, примитивнийший рефлекшон и получилась самодостаточная среда для компонентного программирования не требующая костылей вроде КОМ-а.
Конечно. Потому как в реальной жизни паттерн "делегат", т.е. указатель на метод + указатель на объект, встречается гораздо чаще, чем всё остальное вместе взятое. В Delphi взяли наиболее популярные паттерны визуальной разработки и засунули в язык. VD>Плюсам бы такое "всего то". Ну, или Дельфям шаблоны с операторами.
Ну, я бы предпочел паттерн типа "Итератор". Наверное.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.