Здравствуйте, 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>> Они даже могут быть обобщенными. Ну, что-то вроде: > 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, Вы писали:
VD>Создания чего? Метода? Да не сомненно.
В точке создания замыкания, там где new delegate() {...}. Там захватывается текущий контекст — биндинги переменных.
VD>Ты очередной раз умудрился не понять, что я говорю. Еще раз. Closur != анонимным методам (или если угодно, ламбдам). Closur == делегат.
Не понял, к чему это? Я про возможность.
VD>И на этом уровне проблем вообще нет. Почитай хотя бы документацию по Дельфи.
Что я там должен найти?
VD>Ну, а что до анонимных методов, то опять же можно не давать модифицировать контекст (как это делается в функциональных языках). Тоже решение. В общем, решений может быть масса. Было бы желание их искать.
Дык проблема-то не только в модификации! Проблема в том, что локальная переменная просто перестает существовать при выходе из метода, а замыкание все еще может быть. И в наивной реализации, если мы его вызовем, то оно обратится к несуществующей переменной и попортит стек.
Здравствуйте, WFrag, Вы писали:
WF>Дык проблема-то не только в модификации! Проблема в том, что локальная переменная просто перестает существовать при выходе из метода, а замыкание все еще может быть. И в наивной реализации, если мы его вызовем, то оно обратится к несуществующей переменной и попортит стек.
Что-то я протупил. Действительно, в этом случае можно просто полностью скопировать контекст. Правда, остается другая проблема. Если захваченная локальная переменная — указатель (немодифицируемый), указывающий на другую локальную переменную. Указатель скопируется, но то, на что он указывал — помрет.
VladD2 wrote:
> WF>Нет, я хочу сказать что проблема довольно серьезная и вряд ли > вообще решаема без серьезных изменений (например, GC). Поэтому твои > лихие слова о тараканах в голове мне и не нравятся. Не так все просто, > как мне кажется. > Ты очередной раз умудрился не понять, что я говорю. Еще раз. *Closur > != анонимным методам* (или если угодно, *ламбдам*). Closur == делегат. > И на этом уровне проблем вообще нет. Почитай хотя бы документацию по > Дельфи.
В Дельфи нет замыканий, а есть делегаты, названные "замыканиями".
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
досрочно прекращается вызов сигналов.
Здравствуйте, 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>досрочно прекращается вызов сигналов.
Честно говоря, на мой взгляд, выглядит как совершенно непонятная каша. Можешь задачу словами описать?
Здравствуйте, Cyberax, Вы писали:
C>VladD2 wrote:
>> Ты очередной раз умудрился не понять, что я говорю. Еще раз. *Closur >> != анонимным методам* (или если угодно, *ламбдам*). Closur == делегат. >> И на этом уровне проблем вообще нет. Почитай хотя бы документацию по >> Дельфи.
C>В Дельфи нет замыканий, а есть делегаты, названные "замыканиями".
C>Вообще, вот статья: C>http://en.wikipedia.org/wiki/Closure_%28computer_science%29
Весь прикол в том, что свои, э-э-э..., убеждения Влад черпает именно из этой статьи.
Здравствуйте, 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++.
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. Каждый обработчик возвращает целое число, после обработки всех
сигналов я должен получить список возвращенных значений.
eao197 wrote:
> VD>Возможность создать экземлпяр делегата в рантайме и привезать его к > произвольному методу не извесному на момент компиляции. Это конечно > тоже упирается в убогость рантайма С++, но если верить слухам о > появлении в плюсах в каком-то виде рефлекшона, то такая возможность > была бы очень востребована. Лично я очень часто использую делегаты > именно как решение рантаймных проблем. > А откуда слухи о появлении в C++ рефлекшена?
Это не слухи, Страуструп усиленно продвигает XTI еще с 99 года.
eao197 wrote:
>>> А откуда слухи о появлении в C++ рефлекшена? > C>Это не слухи, Страуструп усиленно продвигает XTI еще с 99 года. > А точной ссылкой на описание XTI не поделишься?
Здравствуйте, 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>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.