A2 & Oberon » Программирование » ActiveOberon » Делегаты

Страниц (2): [1] 2 »
 

1. lit-uriy - 04 Января, 2009 - 06:30:09 - перейти к сообщению
с чем едят эти самые делигаты?
Приер из модуля WMComponents.Mod:
PointerHandler*  = PROCEDURE {DELEGATE} (x, y : LONGINT; keys : SET; VAR handled : BOOLEAN);


Что собственно эта запись означает? (числится в типах)
2. Wlad - 04 Января, 2009 - 12:13:02 - перейти к сообщению
lit-uriy пишет:
с чем едят эти самые делигаты?
Приер из модуля WMComponents.Mod:
PointerHandler*  = PROCEDURE {DELEGATE} (x, y : LONGINT; keys : SET; VAR handled : BOOLEAN);


Что собственно эта запись означает? (числится в типах)

Да примерно то же самое, что и тип делегата в Си-шарпе.
То есть вы можете объявить в любом месте переменную типа этого делегата и присваивать ей ссылку на любой метод любого экземпляра любого класса, если сигнатура этого метода совпадает с описанием типа данного делегата.
Но, в отличие от Си-шарпа, можно и просто присвоить ссылку на процедуру модуля (то есть, не описанную в объекте).
3. BohdanT - 04 Января, 2009 - 12:22:34 - перейти к сообщению
Делегат (англ. delegates) — типобезопасный указатель на функцию.
Делегаты введены для определения прототипа функции обратного вызова.



TYPE
(** Installable event preview handlers. Are called by the components sequencer thread *)
PointerHandler* = PROCEDURE {DELEGATE} (x, y : LONGINT; keys : SET; VAR handled : BOOLEAN);
.....
VisualComponent* = OBJECT(Component)
VAR
(*Обявляем переменные*)
extPointerDown, extPointerUp, extPointerMove : PointerHandler;
.....
(*Устанавливаем*)
PROCEDURE SetExtPointerMoveHandler*(handler : PointerHandler);
BEGIN
Acquire; extPointerMove := handler; Release
END SetExtPointerMoveHandler;
.....
(*Работаем с делегатом*)
IF extPointerMove # NIL THEN extPointerMove(msg.x, msg.y, msg.flags, handled) END;

.....
(*Устанавливаем обработчик в своем компоненте*)
selectedObj.SetExtPointerMoveHandler(HandlePointerMove);


(Добавление)
{DELEGATE}
Делегаты подобны процедурным типам; они совместимы как с процедурами так и с методами, в то время как процедурные типы совместимы только с процедурами.

Делегаты процедурных типов помечаются модификатором DELEGATE. Делегатам могут быть назначены процедуры и методы. Пусть даны переменная с процедурным типом t, экземпляр объекта o и метод M связанный с o, тогда можно записать o.M в t, если конечно метод и t обладают совместимыми сигнатурами. Ссылка на сам объект исключается из сигнатуры процедурного типа. Всякий раз при вызове t назначенный объект o явно передается в self-ссылку (self-reference). Присваивания и вызовы процедур остаются совместимыми с описанием Oberon.
Нетрассируемые указатели — это указатели, которые не отслеживаются сборщиком мусора. Структура или объект, на которые ссылаются только нетрассируемые указатели, могут быть в любой момент утилизированы сборщиком мусора.
4. Wlad - 04 Января, 2009 - 13:43:50 - перейти к сообщению
BohdanT пишет:
Нетрассируемые указатели — это указатели, которые не отслеживаются сборщиком мусора. Структура или объект, на которые ссылаются только нетрассируемые указатели, могут быть в любой момент утилизированы сборщиком мусора.

Вот, кстати, Богдан, эти две фразы мне много раз попадались в сети на счёт АО(А2) нетрассируемых указателей...
Тут ошибочки нет случаем? Противречия? В смысле забирания в любой момент сборщиком мусора... Ежели они им не отслеживаются...
Взять в сравнение КП, так там именно для этого нетрассируемость указателя и объявляется: 1) мы сами следим за указателем 2) что бы система сборки мусора НЕ трогала наши указатели... 3) для совместимости с системой исполнения подлежащей ОСи - у нас ведь указатель уже может исчезнуть из "поля зрения", а в недрах ОСи (куда мы его, например, в виде аргумента функции) передали, он ещё действителен...
Или в связи с тем, что в случае А2 "подлежащей системы", чуждой А2 нет, дисциплина меняется?
Тогда совсем не понятно - что это за указатели, которые у нас в любой момент могут "из рук выхватить"? Улыбка
5. lit-uriy - 04 Января, 2009 - 14:01:09 - перейти к сообщению
Wlad
Wlad пишет:
Тут ошибочки нет случаем? Противречия?
у меня к стати тоже сомнения, надо в оригинал глянуть. а то не логично как-то
(Добавление)
Wlad пишет:
Да примерно то же самое, что и тип делегата в Си-шарпе.
Я о существовании С# лишь слышал
(Добавление)
Все равно небельмеса не понял.
Вот есть в С/С++ указатели на функции, А в борландовском паскале подобное нзывалось процедурный тип, который вроде в Обероне отсутствует.

Дак вот это тоже самое или нет?
(Добавление)
разглядывал я такой пример:

TYPE
MediaPlayer = OBJECT
PROCEDURE Start; .... play a movie .... END Start;
PROCEDURE Stop; .... stop movie .... END Stop;
END MediaPlayer;

ClickProc = PROCEDURE {DELEGATE} (button: Button);
Button = OBJECT
VAR
onClick: ClickProc;
caption: ARRAY 32 OF CHAR;

PROCEDURE OnClick;
BEGIN onClick(SELF) END OnClick;

PROCEDURE & Init(caption: ARRAY OF CHAR; onClick: ClickProc);
BEGIN SELF.onClick := onClick; COPY(caption, SELF.caption)
END Init;
END Button;

PROCEDURE Init(p: MediaPlayer);
VAR b0, b1, b2: Button;
BEGIN
(* Reboot -> call system reboot function *)
NEW(b0, "Reboot", System.Reboot);

(* MediaPlayer UI: bind buttons with player instance *)
NEW(b1, "Play", p.Play);
NEW(b2, "Stop", p.Stop);
END Init;

(Добавление)
взятый тут
во-первых, я думаю есть опечатка в 28 строке (p.Play вместо p.Start);
во-вторых, указатель на процедуру (собственно делегатом помечен) имеет такую сигнатуру:
(button: Button)

а в строке 28 и 29 в конструктор кнопки передается метод p.Stop, имеющий такую сигнатуру:
__
т.е. ничего, а поидее должны быть одинаковы

П.С. мозг уже почти выкипел, спасайте.
6. Wlad - 04 Января, 2009 - 15:25:04 - перейти к сообщению
lit-uriy пишет:
Дак вот это тоже самое или нет?.

Ну, вопсчем, считайте, что - ДА. Улыбка
Единственно, с ассоциацией с Си++ - поосторожней. Там указатели на методы, скорее НЕ указатели, а ... индексы... Если от этого вам полегчает... Улыбка

В приведённом примере - да - есть ошибки. С названием вызываемого метода и с сигнатурами ссылаемых методов. Описание делегата не должно содержать аргументов типа кнопки.

Для себя примите, что указатель на метод (делегат) - не просто указатель, а - некий объект из пары указателей. Один из указателей - ссылка на метод, а второй - указатель на экземпляр объекта, в описании класса которого описан этот метод. Просто в случае указателей на процедуру-НЕ метод (описанную в модуле и вне всех объектов), указатель на экземпляр содержит NIL (на самом деле это не всегда и не совсем так, но сейчас Вам лучше не заморачиваться Улыбка )...
7. MaDzi - 04 Января, 2009 - 15:29:53 - перейти к сообщению
lit-uriy пишет:
П.С. мозг уже почти выкипел, спасайте.


Давайте разбираться. Только предлагаю взять не сомнительный код, который не проверялся на системе, а вполне конкретный модуль из поставки.


MODULE GenericSort; (** AUTHOR "Luc Blaeser"; PURPOSE "Generic Sort Functionality" *)
(** Модуль занимается сортировкой всего и вся *)

TYPE
GenericArray* = POINTER TO ARRAY OF ANY;
(** Определяется массив указателей на что-либо *)
GenericCompareFunct* = PROCEDURE {DELEGATE} (obj1, obj2: ANY): BOOLEAN;
(** Вот он делегат, процедура которая производит сравнение двух объектов *)
(** Функция должна вернуть TRUE только когда obj1 < obj2 *)

(** Процедура реализующая быструю сортировку, принимает в качестве параметров массив указателей и процедуру сравнения (делегат) *)
PROCEDURE QuickSort*(VAR genArray: GenericArray; compFunc: GenericCompareFunct);
BEGIN
QuickSortRec(genArray, compFunc, 0, LEN(genArray)-1)
END QuickSort;

(** Процедура непосредственно реализующая сортировку *)
PROCEDURE QuickSortRec(VAR genArray: GenericArray; comp: GenericCompareFunct; lo, hi: LONGINT);
VAR i, j: LONGINT; x, t: ANY;
BEGIN
i := lo; j := hi;
x := genArray[(lo+hi) DIV 2];

WHILE (i <= j) DO
(** Собственно вызовы делегатов *)
WHILE (comp(genArray[i], x)) DO INC(i) END;
WHILE (comp(x, genArray[j])) DO DEC(j) END;
IF (i <= j) THEN
t := genArray[i]; genArray[i] := genArray[j]; genArray[j] := t;
INC(i); DEC(j)
END
END;

IF (lo < j) THEN QuickSortRec(genArray, comp, lo, j) END;
IF (i < hi) THEN QuickSortRec(genArray, comp, i, hi) END
END QuickSortRec;

END GenericSort.

(Добавление)
Модуль WebStd.Mod, где используется сортировка

Далее объект, который реализует делегатную функцию:

PersistentDataSorter = OBJECT
VAR
comp: PersistentDataCompare;

PROCEDURE &Init*(persComp: PersistentDataCompare);
BEGIN (* persComp # NIL *)
comp := persComp
END Init;

PROCEDURE GenericCompare(obj1, obj2: ANY): BOOLEAN;
VAR persO1, persO2: PersistentDataObject;
BEGIN
persO1 := obj1(PersistentDataObject); persO2 := obj2(PersistentDataObject);
RETURN comp(persO1, persO2)
END GenericCompare;
END PersistentDataSorter;

Обратите внимание, процедура полностью совпадает по сигнатуре.

И непосредственно применение делегата

PROCEDURE GetElementList*(filter: PersistentDataFilter; persComp: PersistentDataCompare) : PersistentDataObjectList;
VAR i: LONGINT; filteredList: TFClasses.List; persList: PersistentDataObjectList; p: ANY; obj: PersistentDataObject;
genArray: GenericSort.GenericArray; persSorter: PersistentDataSorter;
BEGIN
NEW (filteredList);
IF (filter = NIL) THEN filter := DefaultPersistentDataFilter END;
dataObjList.Lock;
FOR i := 0 TO dataObjList.GetCount()-1 DO
p := dataObjList.GetItem(i); obj := p(PersistentDataObject); (* obj # NIL & obj.oid # 0 since it was registered in prevalence system*)
IF (filter(obj)) THEN
filteredList.Add(obj)
END
END;
dataObjList.Unlock;
IF (filteredList.GetCount() > 0) THEN
NEW(genArray, filteredList.GetCount());
FOR i := 0 TO filteredList.GetCount()-1 DO
genArray[i] := filteredList.GetItem(i)
END;
IF (persComp # NIL) THEN
NEW(persSorter, persComp);
GenericSort.QuickSort(genArray, persSorter.GenericCompare)
END;
NEW(persList, LEN(genArray));
FOR i := 0 TO LEN(genArray)-1 DO
persList[i] := genArray[i](PersistentDataObject)
END;
RETURN persList
ELSE
RETURN NIL
END
END GetElementList;
8. BohdanT - 04 Января, 2009 - 15:51:56 - перейти к сообщению
что т я не ппойму, а в чем вопрос собственно?
9. lit-uriy - 04 Января, 2009 - 16:26:04 - перейти к сообщению
так
1) пример значит кривой в оф.доке Не понял
2) делегат - универсальный указатель на процедуру модуля/типа
(в С++ нельзя создать указатель на функцию-член любого класса, только данного конкретного. Поэтому есть довольно много реализаций делегатов, типа кто круче напишет)
3) сигнатуры должны железно совпадать.

Ну тогда можно спать спокойно. Спасибо всем за помощь.
(Добавление)
ага вот еще вопрос применительно к Активному Оберону. А через делегат вызов осуществляется немедленно, т.е. как вслучае прямого вызова процедуры. Или это может откладыватся в некоторых случаях (многопоточная работа)?
10. BohdanT - 04 Января, 2009 - 16:51:12 - перейти к сообщению
lit-uriy пишет:
ага вот еще вопрос применительно к Активному Оберону. А через делегат вызов осуществляется немедленно, т.е. как вслучае прямого вызова процедуры. Или это может откладыватся в некоторых случаях (многопоточная работа)?

Всегда можно глянуть сгенерированный код Подмигивание

Powered by ExBB
ExBB FM 1.0 RC1 by TvoyWeb.ru
InvisionExBB Style converted by Markus®

[Script Execution time: 0.0177]     [ Gzipped ]