2014 dxdy logo

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

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




На страницу Пред.  1, 2, 3, 4  След.
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение12.05.2015, 15:27 
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 
aa_dav в сообщении #1013779 писал(а):
Но это всё такой же способ отправки сообщения.
Ну да, если там первым аргументом стоит объект, которому отправляем, и если на месте описания функции, указатель на которую используется, вообще есть доступ к этому объекту. А если нет?

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

 
 
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 04:47 
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 
arseniiv в сообщении #1014263 писал(а):
.


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

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


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

 
 
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 06:18 
iifat в сообщении #1014266 писал(а):
Вы таки забыли про наследование. Когда вспомните — сильно удивитесь.
А, ну да, с поправками. Да, плохо написал.

 
 
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 07:43 
aa_dav в сообщении #1014271 писал(а):
c.is_inside
Печальное наследие Цэ, не имеющее отношения к ООП, имхо. В любом нормальном языке сюда можно вписать крохотную функцию (не имя, как в Цэ, а определение). Среди этих нормальных есть ООП и не-ООП языки.

 
 
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 08:12 
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 
Таки ж да, дело полезное, не отрицаю. Но, положа руку на сердце,
Используется синтаксис C++
(INT i)VOID:c.is_inside(i)
(Algol-68, Яву не знаю принципиально) ужас, конечно, но не ужас-ужас. Зато, в качестве полезности, позволяет добавить к вызову метода чего-нить маленького.

 
 
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 10:30 
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 
aa_dav в сообщении #1014301 писал(а):
Более того в С++11 узаконили
Рад за них. И тридцати лет не прошло, как в Цэ появились кложуры!
aa_dav в сообщении #1014301 писал(а):
Но это на самом деле полумеры в контексте того о чём я говорил
Хм. Перечитал внимательно то, что вы говорили. Нашёл два аргумента:
aa_dav в сообщении #1014281 писал(а):
Ну вариант, но мне он не нравится
aa_dav в сообщении #1014281 писал(а):
С машинной точки зрения это просто и эффективно
По первому: признаю за вами право на необоснованные предпочтения в любой области. Ну вот вам не нравятся кложуры как метод реализации делегатов, а мне — дополнительные конструкции языка узкого применения. По крайней мере, мы согласны, что в языке должны присутствовать либо кложуры, либо делегаты, иначе громоздко получается.
По второму — ну, мало-мальски разумный компилятор реализует кложуру не менее эффективно, чем делегата.

 
 
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 13:23 
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 
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 
nondeterminism в сообщении #1014388 писал(а):
Явно колбек является избыточным.


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

 
 
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 13:38 
aa_dav в сообщении #1014394 писал(а):
nondeterminism в сообщении #1014388 писал(а):
Явно колбек является избыточным.


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

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

 
 
 
 Re: Фреймы Минского и ООП - что раньше?
Сообщение13.05.2015, 13:43 
nondeterminism в сообщении #1014397 писал(а):
Для этого достаточно сообщения.


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

 
 
 [ Сообщений: 53 ]  На страницу Пред.  1, 2, 3, 4  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group