2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3, 4
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 13:55 


07/05/15

110
aa_dav в сообщении #1014399 писал(а):
nondeterminism в сообщении #1014397 писал(а):
Для этого достаточно сообщения.


Ну я вообще то говорю, что коллбек это и есть один из способов дать сообщение объекту, поэтому для меня это звучит как "Для сообщения достаточно сообщения".

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

 Профиль  
                  
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 14:04 


11/12/14
893
nondeterminism в сообщении #1014405 писал(а):
Если взять Ваш пример с кнопкой, то разница такая(псевдокод)


Нет, первая строка уже есть коллбек. Раз уж мы говорим про ООП, то вот конкретика:
Код:
form.buttonOk.onClick = form.onOkClick;
form.buttonCancel.onClick = form.onCancelClick;

Здесь мы просто указываем, что кнопка "ок" при нажатии должна вызвать метод формы onOkClick, а кнопка "cancel" соответственно onCancelClick.
Промежуточных ни функций ни кложур тут не надо.

-- 13.05.2015, 15:15 --

nondeterminism в сообщении #1014405 писал(а):
коллбек является частью сообщения, а не самим сообщением


Ну блин, я же начал с того, что сказал, что делегат (как ООП-нутый коллбек) это очень хороший и нужный _способ_ послать сообщение. Заранее неизвестному не только объекту, но и его методу, главное чтобы сигнатура совпадала. Это один из механизмов динамической диспетчеризации, весьма полезный в типизированных и компилируемых языках.
Если в каких нибудь CLOS-ах насколько я понимаю что-то иное, то ок. Не буду спорить что есть иные методы динамической диспетчеризации, чем то удобнее и так далее.

 Профиль  
                  
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 14:19 


07/05/15

110
aa_dav в сообщении #1014408 писал(а):

Нет, первая строка уже есть коллбек.


С точки зрения семантики сообщений это не коллбек, а именно само сообщение. Путаница эта идет на мой взгляд отсюда. Рассмотрим 2 варианта назначения обработчика.
Код:

Event := Object clone do(
activate := method("hello" println; onEvent call)
setHandler := method(b, self onEvent := b)
)

event1 := Event clone
event1 setHandler(block("good bye" println))
event1 activate


event2 := Event clone
event2 onEvent := block("bye bye" print)
event2 activate

# ::: hello
# ::: good bye

# ::: hello
# ::: bye bye


В первом варианте, используется коллбек, для назначения обработчика. Фактически, он не нужен, что видно из второго варианта. Но в силу кривизны дизайна, во многих ЯП и соответствующих API используется именно первый вариант. Во втором варианте нет никакого обратного вызова.

Грубо говоря, где то на уровне языка, захардкорено имя обработчика события, например "jnClick". Но пользователю не предоставляют непосредственный доступ к назначеню обработчика, только через какую нибудь нативную функцию, типа, addClickLictener, например. В итоге, пользователь пишет addClickLictener(myHandler) и на уровне ЯП этот handler связывается с этим недоступным извне именем. button onClick=myHandler. Коллбек, в данном случае, это не сообщение объекту, а назначение этого сообщения.

 Профиль  
                  
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 14:27 


11/12/14
893
nondeterminism в сообщении #1014414 писал(а):
В первом варианте, используется коллбек, для назначения обработчика.


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

 Профиль  
                  
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 14:40 


07/05/15

110
aa_dav в сообщении #1014418 писал(а):
nondeterminism в сообщении #1014414 писал(а):
В первом варианте, используется коллбек, для назначения обработчика.


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

Да, именно так я и понимаю (я там дополнил, как раз об этом). По моему Это Вы не совсем понимаете что такое сообщение.
<объект> <сообщение> -- только это, и ничего другого. например, <myobject><mymethod(optional parameters)>
коллбэк тут никаким боком не лезет, он может быть частью optional parameters, но никак не самим собщением. Просто по определению.

Вообще, строго говоря, понятие коллбек относится именно к обратному вызову, к объектам оо вообще не имеет никакого отношения. Вы подаете какой-то ф-ции другую ф-цию в качестве аргумента, и эта ф-ция изнутри вызывается. Более -- ничего. Никакой связи с объектами и сообщениями тут нет

 Профиль  
                  
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 14:51 


11/12/14
893
nondeterminism в сообщении #1014423 писал(а):
коллбэк тут никаким боком не лезет


Так, давайте немножко сузим терминологию.
Мы тут говорим на самом деле про делегаты.
Если посылка сообщения "обычным" способом это
myobject.mymethod(parameters)
то посылка сообщения посредством делегата это
delegate(parameters)
при этом до этой посылки делегат должен быть проинициализирован:
delegate = myobject.mymethod
что происходит - происходит лишь упаковка информации об myobject и mymethod в делегат.
а посылка сообщения никуда не девается и всё делается ради неё.

 Профиль  
                  
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 17:27 
Заслуженный участник


16/02/13
4110
Владивосток
aa_dav в сообщении #1014387 писал(а):
Причём поистине в С++-way
Да уж, этого у него не отнять :wink:
aa_dav в сообщении #1014387 писал(а):
время существования переменной на которую идёт ссылка нуждается в прямых руках
Ну, необходимость прямых рук — это C++-way, унаследованный от Цэ. У ++ требования к радиусу прямизны снижены, но таки да, не до нуля. Впрочем, ну а как вы себе представляете этот контроль в случае простых делегаторов?
М-да, дальше у вас идут глубины ++, до которых я не доныривал. Пытаюсь следить за ходом мысли, но не уверен, что получается. Вот начиная с этого места:
aa_dav в сообщении #1014387 писал(а):
Одно из последствий этого подхода - все С++-лямбды являются объектами РАЗНЫХ классов, даже если они абсолютно идиентичны или совпадают по сигнатурам. Поэтому это еще не делегат
Почему все лямбды разных классов? Точнее говоря, какой из этого проистекает проблем? ++ — полностью типизированный язык; следовательно, аргумент-делегат имеет некоторый фиксированный тип, пусть даже этот тип есть signature {operator ();}. Что именно
aa_dav в сообщении #1014387 писал(а):
копировать и вызывать делегаты между собой ориентируясь только на сигнатуру метода, без фиксации на том что там за класс и объект внутри
вы собрались тут делать? В общем-то, единственное, что можно делать с делегатом, кроме как вызвать, ну ещё хранить, организовывать в списки и т.п., что, насколько могу судить, легко делается описанным вами механизмом?
aa_dav в сообщении #1014387 писал(а):
В gnu-std реализация std::function
Вот тут я вас окончательно покидаю ввиду слабого знакомства с предметом. Замечу только вот тут:
aa_dav в сообщении #1014387 писал(а):
Таким образом то что в грёбанном Дельфи было внутри структурой из двух указателей
(Хриплым шёпотом: не обзывайте Паскаль! Модераторы его трогательно любят. Я уже получил предупреждение за цитату из, по-моему, Ершова) Паскаль не стоит, имхо, приводить в пример. Это нечто гораздо более простое, чем ++. Возьмите хоть механизм передачи параметров. Да, он проще, в ++ передача (если не использовать ссылки) сопряжена с вызовом конструктора копирования, так что да, делегаты в Паскале попроще.

 Профиль  
                  
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 17:54 


11/12/14
893
iifat в сообщении #1014495 писал(а):
Почему все лямбды разных классов? Точнее говоря, какой из этого проистекает проблем?

Ну лямбда просто генерирует класс с перегруженным operator() и в месте встречи себя вставляет инстанс этого класса. Единожды. Поэтому вот какая проблема:
Используется синтаксис C++
class F1
{
   int operator( int i ) { return i * i; };
};
class F2
{
   int operator( int i ) { return i * i; };
};
...
F1 f1;
F2 f2;
...
f1 = f2; // !!! ooops. error.
 

А для делегатов нужно что? Нужно чтобы вы могли присвоить button.onClick = ...; Если разбираться, то если у onClick тип конкретного функтора, то вы не можете ему присвоить другой функтор. Не поможет даже наследование, т.к. просто присвоить наследника родителю для С++-ных value-type-ов это по сути отбросить всё от наследника. Чтобы полиморфизм работал надо работать через ссылки или указатели. Получается что нам нужен какой то промежуточный тип с конкретным размером, конкретного класса, чтобы мог копироваться, мог инвоцироваться и как то под собой скрывал настоящий актуальный функтор. И тут тоже красивый приём есть который я упоминал - type erasure. Действительно красивая штука, простенький пример:
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
class Invoker
{
public:
    virtual void invoke();
};
template<class T>
class InvokerImplementer: public Invoker
{
public:
    T entity;
    InvokerImplementer( T e ): entity( e ) { };
    /*virtual*/ void invoke() { entity(); };
};
class Concrete
{
    Invoker *invoker;
    template<class T>
        Concrete( T functor ) { invoker = new InvokerImplementer<T>(functor); };
    ~Concrete() { delete invoker; };
    void invoke() { invoker->invoke(); };
};
 

Смотрите что происходит - класс Invoker это "перемычка". Это обычный класс фиксированного размера с виртуальной функцией. Сам он нас не интересует.
Мы создаём полностью шаблонный класс InvokerImplementer, который имеет размер зависимый от функтора который в него передают. И дергает ему operator() в методе invoke. Он наследник Invoker при этом.
И тут мы подбиваем клинья - мы делаем класс Concrete, который почти весь (!) обычный класс фиксированного размера, может копироваться. В нём единственное данное - указатель на Invoker.
Но у него шаблонный конструктор через который мы можем в момент собственно создания запихать в него произвольный функтор любого типа - инстанциируется и создатся в куче InvokerImplementer для нужного типа, произвольно размера и т .п., а дергать его мы по прежнему будем через указатель на обычный Invoker.
В этом сила, но и появляется слабость индирекции.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 53 ]  На страницу Пред.  1, 2, 3, 4

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group