Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Вызов функции из функции [D7, XP]


Страницы:   1 2 3

Сергей ©   (2011-01-14 22:08:00) 

Вызов функции из функции

Код такой:

type
 TGetMy = procedure() of object;

function MyFunc1(OnGetMy : TGetMy = nil): Boolean;

 procedure EvOnChange(Self, Sender: TObject);
 begin
   if Assigned(OnGetMy) then OnGetMy(); // Âòîðîé âûçîâ.
 end;

var
 Form : TForm;
 EvChange : TMethod;
begin
 if Assigned(OnGetMy) then OnGetMy(); // Ïåðâûé âûçîâ.
 Form := TForm.Create(Application);
 with Form do begin
   with TEdit.Create(Form) do begin
     Parent := Form;
     EvChange.Code := @EvOnChange;
     OnChange := TNotifyEvent(EvChange);
   end;
   // ...
 end;
end;


Проблема в том, что первый вызов OnGetMy проходит, а второй из функции EvOnChange вызывает ошибку Дельфи. Вопрос, как сделать вызов правильно, чтобы ошибки не возникало?


Leonid Troyanovsky   (2011-01-18 22:22:00) [1]


> DiamondShark ©   (18.01.11 20:19) [55]

> Вот простого надёжного решения ты не хочешь, а хитроподвыперднутое
> глюкалово ты хочешь.

Так понятней.
Хорошо описано.

--
Regards, LVT.


DiamondShark   (2011-01-18 20:19:00) [2]


> Сергей   (18.01.11 18:40) [52]
> "Не положено" и "невозможно" - это разные вещи.

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

Так понятнее?

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

Вот простого надёжного решения ты не хочешь, а хитроподвыперднутое глюкалово ты хочешь.

Тебе больше делать нехер? Времени свободного много? Ну сходи с тёлками потуси.


sniknik   (2011-01-18 19:14:00) [3]

> Разве в ява или яваскрипте есть вложенные функции?
в яве не уверен, не писал на ней, а вот в яваскрипте... вот про что говорил
http://javascript.ru/basic/closure
думаю примеров там для ответа на этот вопрос достаточно.


Плохиш   (2011-01-18 18:43:00) [4]


> ... есть еще возможность ..., переходи на яву, хотя, нет,
>  точно за нее не скажу, на яваскрипт, вот там точно, такое
> в порядке вещей.

Разве в ява или яваскрипте есть вложенные функции?


Сергей   (2011-01-18 18:40:00) [5]


> Servy ©   (17.01.11 05:45) [49]
>
> > Опять не то. Задача вызвать функции OnGetMy из функции
> MyFunc1,
> >  а не просто прописать её в OnChange.
>
> Это невозможно. Указатели на локальные процедуры и функции
> не положено сохранять.


"Не положено" и "невозможно" - это разные вещи.


KSergey   (2011-01-17 08:53:00) [6]

> Сергей   (17.01.11 04:29) [47]
> Все эти личностные оценки правильно или не правильно давайте оставим в стороне.

Где здесь личностные оценки?!


sniknik   (2011-01-17 08:14:00) [7]

> Опять не то. Задача вызвать функции OnGetMy из функции MyFunc1, а не просто прописать её в OnChange.
тебе же объяснили причину, она локальная(/адрес), сделай ее глобальной и сможешь указать, и ее (а переменную сохранять рядом как в [4] например).

или опять не то? т.е. уперся в один, невозможный вариант, и "решаешь" его. а нужно решать задачу. а варианты менять, а лучше изначально использовать правильные.

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


Servy   (2011-01-17 05:45:00) [8]


> Опять не то. Задача вызвать функции OnGetMy из функции MyFunc1,
>  а не просто прописать её в OnChange.


Это невозможно. Указатели на локальные процедуры и функции не положено сохранять. Если вы попробуете скомпилировать следующий код:

procedure Test;

 procedure Local;
 begin
   ShowMessage('I am local');
 end;

var
 P: TProcedure;
begin
 P := Local;
end;


То увидите вполне закономерное сообщение об ошибке:

E2094 Local procedure/function 'Local' assigned to procedure variable

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

Решение вам предлагалось еще в [15]:


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


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


Германн   (2011-01-17 05:15:00) [9]


> Задача вызвать функции OnGetMy из функции MyFunc1, а не
> просто прописать её в OnChange.

А ТС продолжает настаивать на своём бреде. :(


Сергей   (2011-01-17 04:29:00) [10]


> sniknik ©   (15.01.11 20:50) [17]
> замени  
>  EvChange.Code := @EvOnChange;
>  OnChange := TNotifyEvent(EvChange);
> на
>  OnChange := TNotifyEvent(OnGetMy); (сохраним переменную
> собственно в объекте)
> и все будет работать


Опять не то. Задача вызвать функции OnGetMy из функции MyFunc1, а не просто прописать её в OnChange.


> Юрий Зотов ©   (16.01.11 08:46) [20]
>
> А ответ на вопрос "как правильно осуществить вызов из примера
> в первом постинге" все же имеется.
>
> Отвечаю: правильно - никак.


Ничего. Все эти личностные оценки правильно или не правильно давайте оставим в стороне.


Leonid Troyanovsky   (2011-01-17 04:06:00) [11]


> Servy ©   (17.01.11 02:44) [43]

> Да. Однако на обсуждаемую спорную ошибку в [22] это никак
> не влияет, негоже сделать вид, что там все окей, позволив
> возможным неопытным читателям этой ветки обмануться, не
> так ли?

По ходу обсуждения я заметил не одну неточность в формулировках,
но не спешил их уточнять, бо поведение ТС к тому не располагало.
ЮЗ, IMHO, имел в этом случае право и  на умышленную неточность.

Ну, а так, конечно, да - все люди ошибаются, и указывать на ошибки
святое форумное дело.

--
Regards, LVT.


Servy   (2011-01-17 03:38:00) [12]


> Вы скачали пример по ссылке в Юрий Зотов ©   (16.01.11 20:
> 08) [26]?
> Вы его проверили? Он работает?


Да, он работает. Как это подтверждает отсутствие в нем обсуждаемой ошибки, явно сформулированной мной в [41]?


> Однако, не стоит обсуждать тут пост [22], если у вас нет
> намерения "поспорить с ЮЗ".


Я не пониманию, исходя из чего единственным допустимым поводом обсуждения поста является намерение "поспорить с ЮЗ". Я против него в целом ничего не имею, все люди ошибаются. Другое дело, что тут почему-то появились люди, упорно утверждающие, что так и надо.


Германн   (2011-01-17 03:16:00) [13]


> Да. Однако на обсуждаемую спорную ошибку в [22] это никак
> не влияет, негоже сделать вид, что там все окей, позволив
> возможным неопытным читателям этой ветки обмануться, не
> так ли?

Вы скачали пример по ссылке в Юрий Зотов ©   (16.01.11 20:08) [26]?
Вы его проверили? Он работает?

Однако, не стоит обсуждать тут пост [22], если у вас нет намерения "поспорить с ЮЗ".


Servy   (2011-01-17 02:44:00) [14]


> Сам сабж - бредовый.


Да. Однако на обсуждаемую спорную ошибку в [22] это никак не влияет, негоже сделать вид, что там все окей, позволив возможным неопытным читателям этой ветки обмануться, не так ли?


Германн   (2011-01-17 02:36:00) [15]


> Германн ©   (17.01.11 01:58) [37]
>
>
> > Вообще-то, если решать задачу
>
> А нужно ли решать эту задачу в "Начинающим"?
> Да ещё и разводить теоретический спор на тему этой задачи?
>
> Сам сабж - бредовый. X-Y-Z
>


Servy   (2011-01-17 02:33:00) [16]


> Ega23 ©   (17.01.11 01:10) [33]
> Он будет показывать ровно то, что должен показывать. Задачи,
>  чтобы это был полноценный TNotifyEvent не было.


Конечно, задача ведь была "сделайте мне как можно более неполноценный TNotifyEvent".


> sniknik ©   (17.01.11 02:09) [40]
> или имеется в виду второй случай с Memo? ну так бысмысленным
> сделал его тот кто вручную составлял и составил неправильно,
>  дал Mem-У Edit. ССЗБ.


Я правильно вас обоих понял: то, что явный параметр TNotifyEvent  - Sender - потерян и не доступен из процедуры, а неявный параметр - Self -  переименован в Sender не является ошибкой в коде [22], а, напротив, является отличным примером написания кода для начинающих? Тогда будет замечательно, если вы потрудитесь обосновать это нелепое с моей точки зрения утверждение.


sniknik   (2011-01-17 02:09:00) [17]

> Self-ом не являющийся.
или имеется в виду второй случай с Memo? ну так бысмысленным сделал его тот кто вручную составлял и составил неправильно, дал Mem-У Edit. ССЗБ.


sniknik   (2011-01-17 02:06:00) [18]

> если решать задачу замены метода на регулярную процедуру
я вообще то изначально был против ее решать... проще/лучше описать типом/классом (что ни добавляет ни байта к коду), чем составлять "вручную" в коде, и утяжелять его.
посмотри примеры [3], [4].
> Ну и для чистоты концепции неплохо бы передавать в Self именно nil, а не бессмысленную ссылку на объект, Self-ом не являющийся.
почему это она бессмысленная? раз объект существует (обьект Edit создали? создали) то есть (должна быть раз предусмотрена) и ссылка на него, но если хочешь добавь в любой пример ([3], [4])  слово class перед procedure и "цель" достигнута.


Servy   (2011-01-17 02:02:00) [19]


> что "сдвигает" параметр, а не меняет их местами из-за имени.
>  т.е. ну, чтобы вам было привычнее напишите так
> procedure Proc(Self: TObject);


Я бы и написал Self, и второй параметр там оставил. Но Юрий Зотов написал там именно Sender. Таким образом, новичок бы логично предположил, что туда передается именно Sender. В коде [22] разницы нет, так как Sender = Self, поэтому я привел другой пример в [32], где Sender и Self различаются. Соответственно, возникает вопрос, намеренно ли в [22] написан Sender (и если так, то зачем, ветка то для начинающих), или это ошибка, которую следует поправить.

Злобный буратино то не я, а автор кода. Я лишь продемонстрировал, что в Sender'е оказывается совсем не Sender, что должно было навести на некоторые мысли доблестного защитника кода из [22], который уверен, что в никаких проблем с сим кодом не наблюдается.

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


Германн   (2011-01-17 01:58:00) [20]


> Вообще-то, если решать задачу

А нужно ли решать эту задачу в "Начинающим"?
Да ещё и разводить теоретический спор на тему этой задачи?
Сам сабж - бредовый. X-Y-Z


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо