2014 dxdy logo

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

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




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


11/12/14
893
P.S.

Покопался немного в вопросе - так и есть. Сам Алан Кей пишет что прото-ООП начиналось в т.ч. с:
Цитата:
the early work of Doug Ross at MIT (AED and earlier) in
which he advocated embedding procedure pointers in data structures,
Sketchpad (which had full polymorphism -- where e.g. the same offset
in its data structure meant "display" and there would be a pointer to
the appropriate routine for the type of object that structure
represented, etc.

В общем да, шло со всех логичных направлений.

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


27/04/09
28128
aa_dav в сообщении #1013779 писал(а):
Но это всё такой же способ отправки сообщения.
Ну да, если там первым аргументом стоит объект, которому отправляем, и если на месте описания функции, указатель на которую используется, вообще есть доступ к этому объекту. А если нет?

aa_dav в сообщении #1013779 писал(а):
Поэтому неправильно говорить что WndProc это не ООП.
А что, тут кто-то это говорит? :shock: (Я бы сказал, но не буду. WndProc — это функция такая. Она не может быть парадигмой программирования. Но не буду, зачем?)

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


16/02/13
4105
Владивосток
arseniiv в сообщении #1013392 писал(а):
Метод — это всё-таки штука одна на все экземпляры класса
Вы таки забыли про наследование. Когда вспомните — сильно удивитесь.
aa_dav в сообщении #1013779 писал(а):
Используется синтаксис C++
auto it = find_if( points.begin(), points.end(), c.is_inside )
А чего именно нельзя писать в современном Цэ? Если вы про auto, то в GCC есть typeof.

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


11/12/14
893
arseniiv в сообщении #1014263 писал(а):
.


Да не суть уже уже подробности вокруг терминологий и частных случаев. Судя по переписке Кэя дело обстояло именно как я и думал - начни программировать графический редактор и опять как в случае ГУИ сделаешь ООП. Ну или "proto-OOP".

iifat в сообщении #1014266 писал(а):
А чего именно нельзя писать в современном Цэ?


конкретно
Используется синтаксис C++
c.is_inside

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


27/04/09
28128
iifat в сообщении #1014266 писал(а):
Вы таки забыли про наследование. Когда вспомните — сильно удивитесь.
А, ну да, с поправками. Да, плохо написал.

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


16/02/13
4105
Владивосток
aa_dav в сообщении #1014271 писал(а):
c.is_inside
Печальное наследие Цэ, не имеющее отношения к ООП, имхо. В любом нормальном языке сюда можно вписать крохотную функцию (не имя, как в Цэ, а определение). Среди этих нормальных есть ООП и не-ООП языки.

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


11/12/14
893
iifat в сообщении #1014277 писал(а):
Печальное наследие Цэ, не имеющее отношения к ООП, имхо.


Эээ, нет. Тут вообще вопрос в другой плоскости лежит, си тут не при чём. Тут речь идёт о том насколько богат ООП-язык теми или иными способами послать собственно сообщение объекту.
Например кроме С++ еще один широкоизвестный язык с отсутствием (встроенных) делегатов - это Java.
В чём суть проблемы - нередко требуется организовать связь между объектами так, чтобы один "активировал" метод другого по наступлению каких то условий и при этом сам по себе имел очень слабое представление что там за объект которому надо послать сообщение, это лишь его параметр.
Классический пример - EventListener с каким нибудь методом onEvent.
В языках с типизацией и без делегатов начинаются пляски с интерфейсами и собственно IEventListener::onEvent.
В Java проблему решали "с другого угла" сделав анонимные классы и даже кложуры насколько я помню. Но всё это довольно неуклюже на мой взгляд. Фактически на почти на каждое событие ты должен создавать анонимный класс-заглушку, который через кложуру будет протягивать событие в целевой класс. Ну вариант, но мне он не нравится.
В то время как еще в бородатом Delphi (в дальнейшем главный архитектор Дельфи работал над C# и там оно тоже есть), где интерфейсов в смысле явы не было (там есть ключевое слово interface но его суть в решении другой проблемы и в базовых библиотеках оно не используется) решили делегатами - специальный тип который хранит ссылку на объект и указатель на начало метода в памяти, при этом "стирая" из своего типа какого именно класса был объект - всё что важно это только сам факт делегата (т.е. это не указатель на функцию, это отдельный тип) и параметры метода. С машинной точки зрения это просто и эффективно - 2 указателя и ни такта лишнего маш-кода. Синтаксис object.method без круглых скобок - создание делегата, применение к нему круглых скобок - вызов метода закапсулированного объекта. При этом важна только сигнатура метода. И это позволяет тупо "линковать" события разных классов в практически произвольном междусобойчике не теряя контроль над типами. Переизобретается оно и в С++, std::function покрывает такую возможность (если гуглить "C++ delegates", то можно увидеть кучу велосипедов) и т.п. в Qt есть сигналы и слоты и т.п. и т.д.
Но пока оно не в ядре языка оно не столь машинноэффективно всё и не красиво-лаконично.

-- 13.05.2015, 09:19 --

P.S.
В std::function, кстати, если в кишки смотреть, происходит на самом деле что-то похожее на яву. Создаётся функтор, который через type-erasure подцепляется к собственно std::function чтобы внешнему миру отсвечивать только сигнатурой метода. Собсно отсюда и некоторая просадка в машинноэффективности. Не говоря о синтаксисе.

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


16/02/13
4105
Владивосток
Таки ж да, дело полезное, не отрицаю. Но, положа руку на сердце,
Используется синтаксис C++
(INT i)VOID:c.is_inside(i)
(Algol-68, Яву не знаю принципиально) ужас, конечно, но не ужас-ужас. Зато, в качестве полезности, позволяет добавить к вызову метода чего-нить маленького.

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


11/12/14
893
iifat в сообщении #1014297 писал(а):
Но, положа руку на сердце...

Более того в С++11 узаконили и там это выглядит как (в контексте приведенного мной примера):
Используется синтаксис C++
[&c](point &p){ return c.is_inside(p) }
 

А можно с помощью оснастки std::bind:
Используется синтаксис C++
std::bind( &circle::is_inside, &c, _1 )
 

Но это на самом деле полумеры в контексте того о чём я говорил... Вообще это всё таки оффтоп, кроме того, что делегаты - отличный способ послать объекту сообщение.
Почему в С++ с делегатами что-то не всё как хотелось бы и почему всякие лямбды и шаблоны тоже хуже чем потенциально могло бы быть для такого языка, который настаивает на эффективности и краткости, тут уже оффтоп всё таки.

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


16/02/13
4105
Владивосток
aa_dav в сообщении #1014301 писал(а):
Более того в С++11 узаконили
Рад за них. И тридцати лет не прошло, как в Цэ появились кложуры!
aa_dav в сообщении #1014301 писал(а):
Но это на самом деле полумеры в контексте того о чём я говорил
Хм. Перечитал внимательно то, что вы говорили. Нашёл два аргумента:
aa_dav в сообщении #1014281 писал(а):
Ну вариант, но мне он не нравится
aa_dav в сообщении #1014281 писал(а):
С машинной точки зрения это просто и эффективно
По первому: признаю за вами право на необоснованные предпочтения в любой области. Ну вот вам не нравятся кложуры как метод реализации делегатов, а мне — дополнительные конструкции языка узкого применения. По крайней мере, мы согласны, что в языке должны присутствовать либо кложуры, либо делегаты, иначе громоздко получается.
По второму — ну, мало-мальски разумный компилятор реализует кложуру не менее эффективно, чем делегата.

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


11/12/14
893
iifat в сообщении #1014340 писал(а):
Рад за них. И тридцати лет не прошло, как в Цэ появились кложуры!


Причём поистине в С++-way. =) Что на самом деле делает эта конструкция - она создаёт класс с переопределенным operator() с аргументами и телом данными в выражении. Далее в этом классе заводятся поля упомянутые в квадратных скобках. Здесь же создаётся экземпляр этого класса в конструктор которого передаются внешние переменные упомянутые в квадратных скобках или по значению (т.е. просто копируются), или по ссылке (если стоит & которую я поставил, тогда время существования переменной на которую идёт ссылка нуждается в прямых руках, ибо никакого "захвата" внешнего контекста не происходит, происходит лишь копирования или ссылки на внешние переменные. в этом смысле замыкание мягко говоря неполноценное.). Т.е. на самом деле это синтаксический сахарок над созданием класса-функтора в экземпляр которого передаётся ссылка на переменную c, а далее экземпляр работает как обычный функтор и ничем иным на самом деле и не является.
Одно из последствий этого подхода - все С++-лямбды являются объектами РАЗНЫХ классов, даже если они абсолютно идиентичны или совпадают по сигнатурам. Поэтому это еще не делегат. (вообще на самом деле для реализации делегатов именно С++-лямбды не нужны, std::bind так и заводит - функтор, типа выводимого из аргументов шаблона)

Делегатом оно становится, когда этот функтор (произвольного типа) упрятывается за "оболочкой" конкретного типа, позволяющей копировать и вызывать делегаты между собой ориентируясь только на сигнатуру метода, без фиксации на том что там за класс и объект внутри.
Тут уже вступает в роль std::function.
В gnu-std реализация std::function для выполнения этой цели производит классический для С++ приём "type erasure". При этом возникает вот какой подвох. Сам класс std::function имеет фиксированный размер и внутреннее обустройство (ну что логично, иначе бы копирование между экземплярами не работало), поэтому вышеупомянутый функтор он вынужден "прятать" в динамическую память. Действительно размер и внутреннее обустройство функтора-заглушки неизвестно, поэтому std::function в код-перемычке в момент инициализации создаёт промежуточный класс-агрегатор для type-erasure который размещается в куче по new и в него уже "загружается" содержимое функтора копированием.
Таким образом то что в грёбанном Дельфи было внутри структурой из двух указателей, легко копируемых и легко инициализируемых, в С++ в gnu-std превращается в момент инициализации в лазание в динамическую память и в косвенную двойную индирекцию при инвокации. (правда тут следует заметить, что std::function умеет намного более, чем делегат, поэтому сравнивать немного некорректно. там где можно обойтись делегатами делегат бы хорошенько выиграл в ряде моментов, но std::function умеет много больше)
В момент инвокации уже всё не так плохо. Можно даже сказать что всё хорошо. Хотя глядя в асмовыхлоп такого я бы не сказал заранее не видя результатов. Но тут уже вопросы современных процессоров. new же, как понимаете, никакой оптимизатор не "вычистит" никогда.
Так что не всё так безоблачно с оптимизациями и так далее.
Ну а синтаксис, сравните как могло бы быть и как есть:
Используется синтаксис C++
std::function<void(int,char*,float)> functor = std::bind( &MyClass::MyMethod, &obj, std::_1, std::_2, std::_3 );
// vs (гипотетически)
void (class *delegate)(int, char*,float) = obj.MyMethod; // class говорит что это не указатель на функцию, а делегат.
// более того без всяких изменений в std можно было бы писать:
std::function<void(int,char*,float)> functor = obj.MyMethod;
// просто потому что делегат как и указатель на функцию тоже внешне для шаблонного когда есть функтор, сущность у которой есть operator()
 

Дело вкуса? Дело оптимизатора?
По моему тут двух мнений быть не может. Если можно упростить и можно ускорить, то если бы насчёт какого то другого языка можно было бы поспорить, то с С++ - нет. С++ всегда шёл под флагом "всё заради эффективности и красоты кода".
Другое дело да, что есть суровая реальность и с ней приходится мирится. Стандартизаторы уже чего только в С++11 не понаввели (если для вас лямбды было новостью, то некоторые вещи просто шокируют), ради эффективности например даже перегрузку r-value-reference (!). Но над делегатами похоже никто вообще не заморачивается. А жаль.

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


07/05/15

110
aa_dav в сообщении #1013758 писал(а):
Более чем естественное для _ООП_ callback-сообщение.


Вообще то, я бы не сказал, что callback является сообщением. Он является частью сообщения. И утверждение, что колбеки являются естественными для Ъ тоже достаточно спорно. Скорей наоборот. Сравните 2 куска
Код:

O := Object clone do(
sumWithoutCallBack := method((a + 1) println)
sumWithCallBack := method(b, b call(a) println)
)

o := O clone do(a := 10)

o sumWithoutCallBack
o sumWithCallBack(block(x, x + 1))


# ::: 11
# ::: 11


Явно колбек является избыточным. Это скорей костыль в недоооп, из-за отсутствия динамического байндинга.

-- 13.05.2015, 14:32 --

aa_dav в сообщении #1013779 писал(а):
и естественно что нам нужна какая то техника чтобы передать поток управления этой сущности. В целом это называется динамическая диспетчеризация. И реализована она может быть массой способов. От лукапов по таблицам идентификаторов, до указателей на функции (привет WndProc) и там до делегатов. Это всё разные способы, но смысл их один - "послать объекту сообщение".

Ъ-способ только один -- лукапы, все остальное -- профанация.
И по-поводу передачи потока управления, это тоже как-то не точно. Если мы имеем дело асинхронными сообщениями, нет там никакой передачи потока управления. В общем случае, это необязательно, иными словами, с точки зрения семантики сообщений.

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


11/12/14
893
nondeterminism в сообщении #1014388 писал(а):
Явно колбек является избыточным.


Эммм... Суммировать с коллбеком я тоже не знаю зачем =)
Про коллбек думать надо в таком, например, контексте - на библиотечную кнопку нажали, а она дёрнула код программиста.

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


07/05/15

110
aa_dav в сообщении #1014394 писал(а):
nondeterminism в сообщении #1014388 писал(а):
Явно колбек является избыточным.


Эммм... Суммировать с коллбеком я тоже не знаю зачем =)
Про коллбек думать надо в таком, например, контексте - на библиотечную кнопку нажали, а она дёрнула код программиста.

Для этого достаточно сообщения.

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


11/12/14
893
nondeterminism в сообщении #1014397 писал(а):
Для этого достаточно сообщения.


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

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

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



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

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


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

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