Сергей Губанов пишет:
> C>Да, а почему сам используешь при этом возможности Object Pascal'я, а не > C>обычный Pascal? > Я не понял Ваш вопрос. Вообще-то я тут говорил про Component Pascal от > Никлауса Вирта. При чем тут борландовские поделки ума не приложу...
Ошибся, как раз Component Pascal и имел в виду...
> C>а покажи на Паскале аналог вот этого: > C>======================================== > C>class Something : public virtual boost::signals::trackable > C>{ > C>public: > C> void processMessage(std::vector<int> some1, double some2) > C> { > C> .... > C> } > C>}; > C>... > C>boost::signal<void(std::vector<int>, double)> sig; > C>Something s1=new Something(); > C>Something s2=new Something(); > C>... > > C>sig.connect(boost::bind(&Something::processMessage,s1,_1,_2)); > C>sig.connect(boost::bind(&Something::processMessage,s2,_1,_2)); > C>sig(param1,param2); > C>delete s1; > C>sig(param1,param2); > C>delete s2; > C>======================================== > > Да, загадали загадку так загадали, ну какой вопрос — такой и ответ, > смотрите: > >TYPE > Something = POINTER TO RECORD (Signals.Trackable) END; > >PROCEDURE ProcessMessage (this: Something; IN some1: ARRAY OF INTEGER; some2: REAL); >BEGIN > (* ... *) >END ProcessMessage; > > >... > >VAR sig: Signal; s1, s2: Something; >BEGIN > NEW(s1); NEW(s2); > sig.Connect(bind(ProcessMessage, s1, _1, _2)); > sig.Connect(bind(ProcessMessage, s2, _1, _2)); > sig(param1, param2); > s1 := NIL; > sig(param1, param2); > s2 := NIL; > >
Э, нет. Во-первых, в моем примере Something это объект, причем он
автоматически отключается от сигнала при уничтожении. Далее, с помощью
boost::bind'а я создаю функтор-адаптер, который позволяет мне подключить
к сигналу обработчик с другой сигнатурой функционального оператора.
Можно еще усложнить пример:
==============
class Something : public virtual boost::signals::trackable
{
public:
void processMessage(std::vector<int> some1, double some2, int
THIRD_PARAMETER)
{
....
}
};
...
boost::signal<void(std::vector<int>, double)> sig;
Something s1=new Something();
Something s2=new Something();
...
sig.connect(boost::bind(&Something::processMessage,s1,_1,_2,111111));
sig.connect(boost::bind(&Something::processMessage,s2,_1,_2,222222));
sig(param1,param2);
delete s1;
sig(param1,param2);
delete s2;
==============
Причем все типы проверяются на этапе компиляции, поэтому такой код:
sig.connect(boost::bind(&Something::processMessage,s2,_1,));
просто не скомпилится.
Здравствуйте, Сергей Губанов, Вы писали:
C>>Да, а почему сам используешь при этом возможности Object Pascal'я, а не C>>обычный Pascal?
СГ>Я не понял Ваш вопрос. Вообще-то я тут говорил про Component Pascal от Никлауса Вирта. При чем тут борландовские поделки ума не приложу...
ИМХО только благодаря "борландовским поделкам" паскаль все еще остается популярным.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Кё>>>OK, аналогично C#. Но как копирование? Как массив копирует объекты при прераспределении памяти — всегда побитово?
СГ>>Что значит перераспределение памяти?
Кё>Добавление еще 100 элементов, когда для них нет размера.
Куда добавляем-то, массив же уже создан...
Нужно вручную создать совершенно другой новый массив, который на 100 элементов длиннее, и вручную скопировать в него то что хотите. О старом массиве забыть.
NEW(tmp, LEN(a) + 100);
FOR i := 0 TO LEN(tmp)-1 DO tmp[i] := a[i] END;
a := tmp;
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Куда добавляем-то, массив же уже создан... СГ>Нужно вручную создать совершенно другой новый массив, который на 100 элементов длиннее, и вручную скопировать в него то что хотите. О старом массиве забыть.
В общем, опять занимаемся изобретением однотипных велосипедов в разных ракурсах. Наличие в языке generic'ов запросто решает эту проблему. Или в "настоящих модульных компонентных ... etc. системах" это не нужно, лишено смысла? Может, все-таки никому не нужны такие вот системы?
З.Ы. Я уж надеялся, что флейм об Обероне ушел в прошлое. Зачем же паутину с него смахивать?
Здравствуйте, Schade, Вы писали:
S> В общем, опять занимаемся изобретением однотипных велосипедов в разных ракурсах. Наличие в языке generic'ов запросто решает эту проблему.
Э-э-э, а какую проблему?
Написать три строчки кода:
NEW(tmp, LEN(a) + 100);
FOR i := 0 TO LEN(tmp)-1 DO tmp[i] := a[i] END;
a := tmp;
это что теперь проблемой называется????
А я то думал, что проблема, это, например, придумать хорошую эвристику для NP-задачи...
Сергей Губанов пишет:
> S> В общем, опять занимаемся изобретением однотипных велосипедов в > разных ракурсах. Наличие в языке generic'ов запросто решает эту проблему. > Э-э-э, а какую проблему? > Написать три строчки кода: > > NEW(tmp, LEN(a) + 100); > FOR i := 0 TO LEN(tmp)-1 DO tmp[i] := a[i] END; > a := tmp; > > это что теперь проблемой называется????
СГ>Да, загадали загадку так загадали, ну какой вопрос — такой и ответ, смотрите:
Мимо Пропущена реализация Signal и функтора, которая собственно и интересует. Вспоминая GC в C# — тут обязательно придется привлечь WeakReferences.
СГ> sig.Connect(bind(ProcessMessage, s1, _1, _2));
Число параметров и типы могут отличаться, короче — быть любыми. Что, будешь писать разные процедуры для каждой новой комбинации?
СГ>Куда добавляем-то, массив же уже создан...
СГ>Нужно вручную создать совершенно другой новый массив, который на 100 элементов длиннее, и вручную скопировать в него то что хотите. О старом массиве забыть.
Ладно, Cray X, я думаю, справится с таким языком
СГ>Написать три строчки кода: СГ>
СГ> NEW(tmp, LEN(a) + 100);
СГ> FOR i := 0 TO LEN(tmp)-1 DO tmp[i] := a[i] END;
СГ> a := tmp;
СГ>
СГ>это что теперь проблемой называется????
СГ>А я то думал, что проблема, это, например, придумать хорошую эвристику для NP-задачи...
Да нет, проблема — это вылавливать в коде на 25000 строк LEN(tmp) вместо LEN(tmp)-1, написанные по привычке tmp[i] := a[i] вместо DeepCopy(tmp[i], a[i]). Причем в разных случая циклы могут чуть-чуть отличаться, как в случае с DeepCopy, например, так что процедурой не отмажешься, и придется в каждый кусок кода вникать. Тут — копирование, там — вставка, там — сдвиг, там — элементы ссылаются на индексы друг друга в этом массиве. Через неделю ты забудешь, что эта программа делает
Здравствуйте, Кодёнок, Вы писали:
Кё> Да нет, проблема — это вылавливать в коде на 25000 строк LEN(tmp) вместо LEN(tmp)-1, написанные по привычке tmp[i] := a[i] вместо DeepCopy(tmp[i], a[i]). Причем в разных случая циклы могут чуть-чуть отличаться, как в случае с DeepCopy, например, так что процедурой не отмажешься, и придется в каждый кусок кода вникать. Тут — копирование, там — вставка, там — сдвиг, там — элементы ссылаются на индексы друг друга в этом массиве. Через неделю ты забудешь, что эта программа делает
Да ладно Вам фантазировать, ничего вылавливать не надо, все пишется в 1 экземпляре в одном модуле.
Здравствуйте, Кодёнок, Вы писали:
Кё>Число параметров и типы могут отличаться, короче — быть любыми. Что, будешь писать разные процедуры для каждой новой комбинации?
Кё>
Ах вот в чем дело. То есть термином "гибкость" здесь названо, то, что другие люди называют термином "грязный хак". Дело в том, что когда возникает необходимость определить процедуру принимающую произвольное количество аргументов различных типов, то это решается элементарнейшим способом:
TYPE
Params = ABSTRACT RECORD END;
PROCEDURE Bind(VAR params: Params);
TYPE
Params1 = RECORD (Params)
(* Какие угодно параметры *)END;
PROCEDURE Bind1(VAR params: Params);
BEGIN
WITH params: Params1 DO(* ... *)ELSE(* ... *)END
END Bind1;
TYPE
Params2 = RECORD (Params)
(* Какие угодно параметры *)END;
PROCEDURE Bind2(VAR params: Params);
BEGIN
WITH params: Params2 DO(* ... *)ELSE(* ... *)END
END Bind2;
СГ>Ах вот в чем дело. То есть термином "гибкость" здесь названо, то, что другие люди называют термином "грязный хак". Дело в том, что когда возникает необходимость определить процедуру принимающую произвольное количество аргументов различных типов, то это решается элементарнейшим способом:
Сам-то понял что написал? Нет ни у меня хака, ни у тебя элементарности.
Здравствуйте, Cyberax, Вы писали:
C>Кстати, а как твоим функциям передавать КОНТЕКСТ вычислений? Или как обычно, через глобальные переменные?
Да.
Только глобальные переменные в модульных языках — это вовсе не тоже самое что глобальные переменные в не модульных языках. В модульных языках все переменные находятся внутри модулей, а модули загружаются в память и выгружаются из нее динамически во время работы программы — то есть никакие они (переменные) вовсе не "глобальные" в строгом смысле этого слова.
Впрочем, если возникает необходимость в нескольких контекстах вычисления одновременно, то Вы правы, тут уже надо использовать ООП, и смысл в именно такой функции какую просил я значительно снижается — ведь можно использовать для того же самого другие средства уже свойственные только ООП.
Сергей Губанов пишет:
> C>Кстати, а как твоим функциям передавать КОНТЕКСТ вычислений? Или как > обычно, через глобальные переменные? > Да.
В морг. СРАЗУ же, без разговоров.
> Только глобальные переменные в модульных языках — это вовсе не тоже > самое что глобальные переменные в не модульных языках. В модульных > языках все переменные находятся внутри модулей, а модули загружаются в > память и выгружаются из нее динамически во время работы программы — то > есть никакие они (переменные) вовсе не "глобальные" в строгом смысле > этого слова.
Плевать, два потока, исполняющие один код я запустить уже не смогу.
Реентерабельности тоже нет. И не нужно говорить, что это все фигня — это
важнейшие вещи.
> Впрочем, если возникает необходимость в нескольких контекстах > вычисления одновременно, то Вы правы, тут уже надо использовать ООП, и > смысл в именно такой функции какую просил я значительно снижается — > ведь можно использовать для того же самого другие средства уже > свойственные только ООП.
А контекст нужно передавать ВСЕГДА (в 99.99% случаев), иногда только
можно для целей оптимизации использовать глобальные переменные.
Сергей Губанов пишет:
> Кё>Число параметров и типы могут отличаться, короче — быть любыми. > Что, будешь писать разные процедуры для каждой новой комбинации? > Кё> > >Кё>PROCEDURE bind_void_void(IN A: PROCEDURE; ...): functor >Кё>PROCEDURE bind_void_int(IN A: PROCEDURE(a:integer); ...): functor >Кё>PROCEDURE bind_void_real(IN A: PROCEDURE(a:read...): functor >Кё>PROCEDURE bind_void_int_real(IN A: PROCEDURE(a:read...) >Кё>PROCEDURE bind_void_real_int(IN A: PROCEDURE(a:read...) >Кё > > > Ах вот в чем дело. То есть термином "гибкость" здесь названо, то, что > другие люди называют термином "грязный хак". Дело в том, что когда > возникает необходимость определить процедуру принимающую произвольное > количество аргументов различных типов, то это решается элементарнейшим > способом:
Не совсем то. Вот есть у меня функциональный оператор с сигнатурой "void
(int,int)", я хочу на него сделать
адаптер вида "void(int)", а второй параметр сделать равным 2. С boost'ом
это делается так:
=============
boost::bind(xxx,указатель_на_функтор,_1,2);
=============
У меня создается функтор, принимающий один параметр, делегирующий вызов
моему функтору, устанавливая второй его параметр в 2.
И еще раз — совместимость типов проверяется на этапе компиляции.
Здравствуйте, Курилка, Вы писали:
К>Т.е. проверку делаем в рантайме со всеми вытекающими (довольно "грязными") последствиями?
В оберонах вообще и в Component Pascal в частности нет множественного наследования, а есть просто расширение типа. В связи с этим инструкция конкретизации типа
WITH v: T1 DO S1 | v: T2 DO S2 | v: T3 DO S3 ... ELSE Sn END
не обладает ни какими грязными последствиями, а также выполняется очень быстро — примерно так же быстро как выполнялся бы обычный CASE (или switch) по скрытому тэгу в записи (ну разьве только что если иерархия расширения типов будет глубокой — вот из-за этого может быть чуток медленнее).
Здравствуйте, Cyberax, Вы писали:
C>Плевать, два потока, исполняющие один код я запустить уже не смогу. C>А контекст нужно передавать ВСЕГДА (в 99.99% случаев), иногда только C>можно для целей оптимизации использовать глобальные переменные.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Здравствуйте, Курилка, Вы писали:
К>>Т.е. проверку делаем в рантайме со всеми вытекающими (довольно "грязными") последствиями?
СГ>В оберонах вообще и в Component Pascal в частности нет множественного наследования, а есть просто расширение типа. В связи с этим инструкция конкретизации типа СГ>
СГ>WITH v: T1 DO S1 | v: T2 DO S2 | v: T3 DO S3 ... ELSE Sn END
СГ>
СГ>не обладает ни какими грязными последствиями, а также выполняется очень быстро — примерно так же быстро как выполнялся бы обычный CASE (или switch) по скрытому тэгу в записи (ну разьве только что если иерархия расширения типов будет глубокой — вот из-за этого может быть чуток медленнее).
С чего это не обладает?
Например:
Берём ситуацию, что в with ты забудешь один из типов по запарке, бывает такое, ну и оберон твой нихрена не скажет, всё будет ништяк, но работать-то будет в итоге прога не правильно.
А в плюсах тебе компилер скажет — нифига нет определения с такими параметрами, соответственно ты прогу даже скомпилить не сможешь.
Что ты скажешь хотябы на это?
Сергей Губанов пишет:
> C>Плевать, два потока, исполняющие один код я запустить уже не смогу. > C>А контекст нужно передавать ВСЕГДА (в 99.99% случаев), иногда только > C>можно для целей оптимизации использовать глобальные переменные. > А если система встроенная и там потоков нет?
Тогда там нечего делать GC, и код следует писать на С/Asm. Кроме того,
проблема реентерабельности никуда не исчезает и без потоков (что будет,
если я захочу два конечных автомата, вызывающих друг друга?).
Кстати, на С такая функция будет выглядеть так:
=========
void* func(void* someFunc)
{
return someFunc;
}
...
void funcPtr=func(&func);
assert(funcPtr==&func);
=========
Хотя нетипобезопасно получается, но во встроенных системах (если уж о
них разговор) это обычно не так важно.