Здравствуйте, netch80, Вы писали:
N>И что хорошего это даёт? Вместо того, чтобы переопределить, например, 2 функции, вписывать их 50? А как быть с тем, что кроме функций там ещё есть поля данных, с которыми им надо работать?
Совсем забыл. Еще такой подход решает проблему комбинаторного взрыва. Если предусмотрено переопределение 50 функций, где-нибудь захочется переопределить какие-то две. В другом месте — другие три. А потом захочется поиметь все вместе. На явном переопределении это делается. При наследовании возникнут большие сложности. Еще хуже будет, если подобных групп несколько.
Здравствуйте, netch80, Вы писали:
N>>>А с чего Вы решили, что речь идёт о той же программе? Я как раз говорил о возможностях библиотеки. Создаётся объект и к нему в следующей версии вводится ещё один настроечный параметр. SV.>>Я решил, что вы ссылаетесь на этот пример:
N>На этот и на второй — с атрибутами треда в pthreads.
SV.>>И речь идет об одной и той же программе — Berkeley DB.
N>Это не программа. Это именно что библиотека — key-value хранилище нескольких типов организацтт (hash, btree, recno) с произвольными (строка байт) ключом и значением. Она сама ничего не может делать, только предоставляет API.
SV.>> Если неправильно понял, поправляйте.
N>Вот, поправил.
Если это библиотека, то я совсем запутался. Протокол беседы, как я ее вижу — Я: "переиспользование кода становится возможным тогда, когда это библиотека/API, которая изначально задумывалась как библиотека/API и делалась прямыми руками". Вы: "Не совсем так", и приводите контр(?)пример — Berkeley DB. Я: вынужденно соглашаюсь и отзываю свой тезис, заменяя его более точным — "переиспользование кода становится возможным тогда, когда это библиотека/API, которая изначально задумывалась как библиотека/API и делалась прямыми руками ИЛИ мы пишем новую версию программы, не являющейся библиотекой/API, на базе старой". С Berkeley DB я, конечно, не знаком, зато узнав, что понятие реюза несколько шире, чем я думал, я вспомнил известные мне проекты, новые версии которых делались на базе старых, и согласился.
По этому пункту победа за вами, но тут оказывается, что Berkeley DB — как раз-таки библиотека. Что же тогда вы имели в виду, написав "Не совсем так"?
Здравствуйте, SV., Вы писали:
SV.>Если это библиотека, то я совсем запутался. Протокол беседы, как я ее вижу — Я: "переиспользование кода становится возможным тогда, когда это библиотека/API, которая изначально задумывалась как библиотека/API и делалась прямыми руками". Вы: "Не совсем так", и приводите контр(?)пример — Berkeley DB.
Нет. Моё "не совсем так" было возражением не на эти слова, а на "то неважно, ООП это, процедуры, или еще что-то" (в том же абзаце). Я доказываю, что объектное построение — подход, который (по сравнению с обычным процедурным) упрощает использование кода, более того — за счёт поддерживаемых свойств является самым надёжным (в плане долговременных последствий) среди всех альтернативных подходов.
SV.>По этому пункту победа за вами, но тут оказывается, что Berkeley DB — как раз-таки библиотека. Что же тогда вы имели в виду, написав "Не совсем так"?
Повторяю: я возражал против следующего тезиса: (выделен в цитате курсивом)
1. Переиспользование кода становится возможным тогда, когда это библиотека/API, которая изначально задумывалась как библиотека/API и делалась прямыми руками. Если это так, то неважно, ООП это, процедуры, или еще что-то. Грамотный ООПщик легко обернет не-ОО библиотеку/API в свои классы.
Я доказываю, что выбор инфраструктуры реализации тут важен, потому что сам стиль интерфейса, когда свойства, настройки, и т.д. сосредоточены в "объекте" (чем бы он ни был), имеет существенное преимущество тем, что устраняет необходимость "таскать" за собой все необходимые параметры, свойства, уточнения того, что хотим сделать, которые чрезвычайно важны для типичной библиотеки; далее, когда это всё сосредоточено в некотором объекте, структура которого нам не важна, открывается обширное поле для оптимизации его работы. Где-то надо держать временный файл постоянно открытым, где-то — делать сложные вычисления параметров, которые лучше делать только один раз, и так далее. Есть хорошая аналогия — если вы поручаете какое-то постоянное дело подчинённому, то надо давать ему задания и требовать отчёта о выполнении, а не руководить каждым взмахом его руки. (Разумеется, есть и отрицательные стороны — он может сделать что-то не так; и функциональность в объекте может требовать лишнего; но какой подход без недостатков?) Чем сложнее задача, тем важнее логическое её представление в виде отдельных сущностей со своим поведением, и тем вероятнее её выигрыш от объектного подхода.
Здравствуйте, samius, Вы писали:
S>То есть вы настаиваете на том, что истинное ООП от неистинного отличает возможность IDE к вываливанию имен методов и построения диаграммы?
Вернемся к началу и попробуем еще раз. Хорошо известное определение:
Object-oriented programming (OOP) is a programming paradigm using "objects" – data structures consisting of data fields and methods together with their interactions – to design applications and computer programs.
Соответствует ли этому определению парадигма MFC? Да, несомненно.
Соответствует ли этому определению парадигма WinAPI? Я считаю, что нет, но другие выражают сомнение: "Это уже объектный подход. Даже если не ООП в полной мере."
Почему нет? Просто по определению. HWND не "data structures consisting of data fields and methods". Откуда же тогда сомнения? Вот откуда: может быть, функции, у которых HWND — первый параметр, мы можем считать за методы?
Так вот, нет, не можем. Машина не может их сгруппировать в общем случае, основываясь только на коде. Не может построить диаграммы отношений. Даже человек, вооруженный знанием, что HWND — не просто указатель, а ручка от окна, не может это сделать однозначно (выбор пера в контекст можно представить двояко — перо использует контекст или наоборот).
S>Не понимаю, что такое "независимая".
Независимая от Микрософта. Я же написал: имелись в виду сценарии, типа, Микрософта, прикручивающего к студии возможность комбинировать функции по HWND.
> Т.е. с одной IDE мы имеем истинный ООП код, а с другой IDE тот же самый код становится "просто объектным" но не истинным?
Слово "истинный" можете игнорировать, оно избыточно. Все, что попадает под определение ООП — ООП, а остальное — нет. Разумеется, использование какой бы то ни было IDE не сделает из ООП-кода не-ООП, или ООП-код из не-ООП. Но IDE можно подкрутить так, что различие станет неочевидным. Поэтому я предложил подкрученные IDE не рассматривать.
SV.>>Можно ввести соглашение, что указатели, чьи typedef'ы начинаются с H — хендлы, но есть гораздо лучшее соглашение: ключевое слово class. S>А как же языки с динамической типизацией? Пусть в них есть слово class, но там один class от другого отличается не больше чем HWND от указателя. Или истинный ООП несовместим с динамической типизацией?
Для языков с динамической типизацией этот пример (пример того, что следует из неООПности WinAPI!) не работает. И что с того?
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, samius, Вы писали:
S>>То есть вы настаиваете на том, что истинное ООП от неистинного отличает возможность IDE к вываливанию имен методов и построения диаграммы?
SV.>Вернемся к началу и попробуем еще раз. Хорошо известное определение:
SV.>http://en.wikipedia.org/wiki/Object-oriented_programming
SV.>
SV.>Object-oriented programming (OOP) is a programming paradigm using "objects" – data structures consisting of data fields and methods together with their interactions – to design applications and computer programs.
Если мы аппелируем к этому определению и в частности к структуре, содержащей поля и "методы" в их ООП трактовке, то мы вынуждены признать что ООП парадигма может существовать лишь в рамках ООП языков. И то возникают вопросы. Так, оказывается что COM не ООП по причине того что интерфейсы не содержат полей данных.
Однако, фундаментальные концепции ООП не требуют полей и методов.
SV.>Соответствует ли этому определению парадигма MFC? Да, несомненно.
Не очень понятно, что такое парадигма MFC. Подход, в котором выполнено MFC? Да, можно считать что MFC тяготеет к OOP. Но сами по себе структуры с полями и методами не являются достаточным условием принадлежности подхода к ООП.
SV.>Соответствует ли этому определению парадигма WinAPI? Я считаю, что нет, но другие выражают сомнение: "Это уже объектный подход. Даже если не ООП в полной мере."
Несомненно объектный подход, судя по перечню фундаментальных концепций ООП.
SV.>Почему нет? Просто по определению. HWND не "data structures consisting of data fields and methods". Откуда же тогда сомнения? Вот откуда: может быть, функции, у которых HWND — первый параметр, мы можем считать за методы?
За методы — не знаю, но за способ отправить сообщение окну — можем. В фундаментальных концепциях описаны минимальные признаки. Методов, полей и структур в них нет.
SV.>Так вот, нет, не можем. Машина не может их сгруппировать в общем случае, основываясь только на коде. Не может построить диаграммы отношений. Даже человек, вооруженный знанием, что HWND — не просто указатель, а ручка от окна, не может это сделать однозначно (выбор пера в контекст можно представить двояко — перо использует контекст или наоборот).
Вот то чего может машина с кодом в отношении диаграмм отношений — это совершенно не относится к ООП. Просто абсолютно.
S>>Не понимаю, что такое "независимая".
SV.>Независимая от Микрософта. Я же написал: имелись в виду сценарии, типа, Микрософта, прикручивающего к студии возможность комбинировать функции по HWND.
А причем тут микрософт? Еще раз отошлю к фундаментальным концепциям ООП. В них нет ничего о возможностях создания диаграмм, плагинов IDE и прочего.
SV.>Слово "истинный" можете игнорировать, оно избыточно. Все, что попадает под определение ООП — ООП, а остальное — нет. Разумеется, использование какой бы то ни было IDE не сделает из ООП-кода не-ООП, или ООП-код из не-ООП. Но IDE можно подкрутить так, что различие станет неочевидным. Поэтому я предложил подкрученные IDE не рассматривать.
А я предлагаю IDE не рассматривать совершенно.
S>>А как же языки с динамической типизацией? Пусть в них есть слово class, но там один class от другого отличается не больше чем HWND от указателя. Или истинный ООП несовместим с динамической типизацией?
SV.>Для языков с динамической типизацией этот пример (пример того, что следует из неООПности WinAPI!) не работает. И что с того?
Можно конкретнее? Что там не работает?
Здравствуйте, mrTwister, Вы писали:
T>Здравствуйте, Undying, Вы писали:
U>>Здравствуйте, mrTwister, Вы писали:
T>>>Вообще-то имеет. Хорошее решение называется SRP. T>>>В твоем примере с textbox'ом можно вынести ответственность по рисованию рамки в отдельную сущность — "рисователь рамки". После чего textBox, а также все, кому надо нарисовать рамку, будут для этого использовать "рисователь рамки".
U>>В общем случае это не помогает.
T>Вообще-то помогает.
Еще добавить IoC и получим классическое чистое ФП, натянутое на кривое ООП. Вместо функций у нас объект "делатель" и вместо ФВП — передача кучи делателей через параметры.
Здравствуйте, mrTwister, Вы писали:
T>Ответ на этот вопрос зависит от ответственностей, которые покрываются данным методом. Я не знаю, что он делаю, и могу только гадать. Предположим, что во время инсталляции он создает базу данных с таблицами. Тогда можно сделать абстракцию:
T>
Здравствуйте, VoidEx, Вы писали:
VE>Еще добавить IoC и получим классическое чистое ФП, натянутое на кривое ООП. Вместо функций у нас объект "делатель" и вместо ФВП — передача кучи делателей через параметры.
Это не функции, а именно объекты (абстракции), в которых может быть состояние и несколько методов. С какого боку тут ФП?
Письмо из будущего. Предположительно из 2021 года.
Почему так получается, что когда код представляет из себя набор метаклассов и метафункций, то такой код очень затруднен для понимания. Точнее трудно понять не столько код, сколько что же это всё вместе генерит и в каком порядке. И это даже при отсутствии злоупотребления препроцессором. С кодом написанным, что называется классически с иерархиями классов, таких проблем нет, и, что характерно, его объём в разы меньше. Я сильно начинаю сомневаться в полезности метапрограммирования. Складывается впечатление, что метапрограммирование это такое хорошо замаскированные современные макросы. И ещё я не понимаю, почему как только люди берутся за проект, то тут же как грибы после дождя начинают появляться метаклассы. На самую простую функциональность количество новых порождённых типов порой приближается к сотни. И почему такая уверенность, что так и надо делать? Как им вдолбить простую истину, высказанную Artifact'ом, что хороший код, это не тот код, в который нечего добавить, а код, из которого нечего выкинуть?
Здравствуйте, netch80, Вы писали:
N>И что хорошего это даёт? Вместо того, чтобы переопределить, например, 2 функции, вписывать их 50? А как быть с тем, что кроме функций там ещё есть поля данных, с которыми им надо работать?
1. Если вам нужны "поля данных", с которыми нужно работать — тогда это повод рассмотреть наследование реализации. Но это бывает значительно реже, чем кажется после прочтения овноучебников.
2. Если у вас в оборачиваемом объекте 50 функций, то стоит задуматься о single responsibility principle. Зачем вам такой интерфейс?
Здравствуйте, mrTwister, Вы писали:
T>Это не функции, а именно объекты (абстракции), в которых может быть состояние и несколько методов. С какого боку тут ФП?
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, mrTwister, Вы писали:
T>>Это не функции, а именно объекты (абстракции), в которых может быть состояние и несколько методов. С какого боку тут ФП?
VE>Рисователь рамки-то?
— Даже если в одном месте будет реализация интерфейса с одним методом и без состояния, это сразу делает всю программу функциональной?
— Если сейчас в интерфейсе один метод и в реализации нет состояния, это еще не значит, что в будущем ничего не изменится. ООП в данном случае предоставит удобную возможность расширения функционала.
— Кроме рисователя рамок задач больше нет?
— "рисователь рамки" — это не просто сигнатура функции, это абстракция, которая олицетворяет собой некоторую ответственность. Вводится разделение между названием абстракции и названием конкретной реализации этой абстракции. С таким кодом проще работать. Например, IDE может по нажатию клавиши предоставить список всех реализаций заданного интерфейса и мне просто надо выбрать из предложенного.
Здравствуйте, samius, Вы писали:
S>Если мы аппелируем к этому определению и в частности к структуре, содержащей поля и "методы" в их ООП трактовке, то мы вынуждены признать что ООП парадигма может существовать лишь в рамках ООП языков. И то возникают вопросы. Так, оказывается что COM не ООП по причине того что интерфейсы не содержат полей данных.
Я не очень понимаю, что такое "ап(п)еллировать к определению". Вы хотите сказать "если мы его примем"? А что, есть основания не принимать?
Утверждение "мы вынуждены признать что ООП парадигма может существовать лишь в рамках ООП языков" таким основанием не является по причине неверности. Есть грязные хаки, которые позволяют работать с объектами на языках типа C. Например, такова технология COM. Объекты от этого не перестают быть объектами, поскольку описаны в явном виде в библиотеке типов, которая считается неотъемлемой частью кода. Все методы и все свойства каждого объекта, исчерпывающе и неизбыточно. К WinAPI, напомню, ничего подобного не прилагается.
Отсюда и все остальное. Зачем переусложнять? Наличие объектов — то есть, полей и методов, объединенных в одно целое — которые взаимодействуют между собой — необходимое и единственное условие ООП.
Здравствуйте, mrTwister, Вы писали:
VE>>Рисователь рамки-то?
T>- Даже если в одном месте будет реализация интерфейса с одним методом и без состояния, это сразу делает всю программу функциональной? T>- Если сейчас в интерфейсе один метод и в реализации нет состояния, это еще не значит, что в будущем ничего не изменится. ООП в данном случае предоставит удобную возможность расширения функционала. T>- Кроме рисователя рамок задач больше нет? T>- "рисователь рамки" — это не просто сигнатура функции, это абстракция, которая олицетворяет собой некоторую ответственность. Вводится разделение между названием абстракции и названием конкретной реализации этой абстракции. С таким кодом проще работать. Например, IDE может по нажатию клавиши предоставить список всех реализаций заданного интерфейса и мне просто надо выбрать из предложенного.
Я вам про фому, а вы мне про ерёму. Я вроде процитировал фразу, на которую отвечал, чо с темы-то съезжать?
Здравствуйте, mrTwister, Вы писали:
T>- Даже если в одном месте будет реализация интерфейса с одним методом и без состояния, это сразу делает всю программу функциональной?
Нет, но это шаг в нужную сторону. T>- Если сейчас в интерфейсе один метод и в реализации нет состояния, это еще не значит, что в будущем ничего не изменится. ООП в данном случае предоставит удобную возможность расширения функционала.
1. Изменение количества методов в ФП достигается очень просто. Нужно два метода — делаем "структуру" из f1() и f2().
2. А вот если рисователю рамок потребуется состояние, то это очень крутая смена сигнатуры у функции "рисуйРамку". У этого решения есть крайне тяжёлые последствия — например, теперь мы не можем быть уверены, что перестановка порядка рисования рамок останется корректной.
T>- "рисователь рамки" — это не просто сигнатура функции, это абстракция, которая олицетворяет собой некоторую ответственность. Вводится разделение между названием абстракции и названием конкретной реализации этой абстракции. С таким кодом проще работать. Например, IDE может по нажатию клавиши предоставить список всех реализаций заданного интерфейса и мне просто надо выбрать из предложенного.
А зачем смешивать IDE и семантику языка? Описанное преимущество — это заслуга статической типизации. Если она же есть в ФП, то теоретически ничто не мешает мне "по нажатию клавиши" получить список всех функций с заданной сигнатурой.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, SV., Вы писали:
SV.>Утверждение "мы вынуждены признать что ООП парадигма может существовать лишь в рамках ООП языков" таким основанием не является по причине неверности. Есть грязные хаки, которые позволяют работать с объектами на языках типа C. Например, такова технология COM. Объекты от этого не перестают быть объектами, поскольку описаны в явном виде в библиотеке типов, которая считается неотъемлемой частью кода. Все методы и все свойства каждого объекта, исчерпывающе и неизбыточно. К WinAPI, напомню, ничего подобного не прилагается.
SV.>Отсюда и все остальное. Зачем переусложнять? Наличие объектов — то есть, полей и методов, объединенных в одно целое — которые взаимодействуют между собой — необходимое и единственное условие ООП.
Никаких полей в COM нет. Посмотрите повнимательнее в IDL — там только методы.
Переусложнением на самом деле является вот эта "вывернутая наизнанку" трактовка ООП, где к данным начинают приделывать методы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>2. А вот если сменил тип переменнойрисователю рамок потребуется состояние, то это очень крутая смена сигнатуры у функции "рисуйРамку". У этого решения есть крайне тяжёлые последствия — например, теперь мы не можем быть уверены, что перестановка порядка рисования рамок останется корректной.
Поэтому компилятор тыкнет в места, где это надо исправить. И именно поэтому чистое ФП и рулит.
Добавил зависимость от порядка, изволь указать.
А то добавил состояние, теперь переставлять нельзя, а код молча компилируется, но не работает.
Здравствуйте, Sinclair, Вы писали:
S>Никаких полей в COM нет. Посмотрите повнимательнее в IDL — там только методы.
IDL — Interface Definition Language, а не Programming Language. Этот язык описывает интерфейс, ООП-маску, которую можно натянуть на что угодно, в том числе на абсолютно не-ООП язык, типа C. Как я понимаю, это и была одна из задач COM'а — создать объектно-ориентированный общий знаменатель самых разных языков. Поэтому, "метод" в IDL может на языке имплементации быть вовсе не методом, а самой обычной глобальной функцией. "Поле" — не полем, а значением в памяти по адресу или на диске в каком-то секторе. Получается этакий виртуальный ООП (не в дебильном новорусском смысле "то, чего не может быть", а в исходном английском — "the quality of having the attributes of something without sharing its (real or imagined) physical form"). И в этом виртуальном ООП'е, описанном на IDL'е, поля, конечно же, есть. С одной стороны, синтаксис их объявления очень похож на синтаксис объявления методов, но нас, компьютерных инженеров, эта похожесть не должна вводить в заблуждение. С другой стороны, он допускает несколько отдельных записей (очень похожих на методы!) на одно поле. В чистом итоге, вы абсолютно однозначно можете отделить метод от поля, а, кроме того, можете написать для этого очень простую программу.
В реальности, конечно, создатели COM'а все сделали для того, чтобы вы виртуальные "поля" реализовывали через методы ООП-языков (в первую очередь — C++), отсюда и синтаксис, но это, извините, не обязательно.
S>Переусложнением на самом деле является вот эта "вывернутая наизнанку" трактовка ООП, где к данным начинают приделывать методы.
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, mrTwister, Вы писали:
VE>>>Рисователь рамки-то?
T>>- Даже если в одном месте будет реализация интерфейса с одним методом и без состояния, это сразу делает всю программу функциональной? T>>- Если сейчас в интерфейсе один метод и в реализации нет состояния, это еще не значит, что в будущем ничего не изменится. ООП в данном случае предоставит удобную возможность расширения функционала. T>>- Кроме рисователя рамок задач больше нет? T>>- "рисователь рамки" — это не просто сигнатура функции, это абстракция, которая олицетворяет собой некоторую ответственность. Вводится разделение между названием абстракции и названием конкретной реализации этой абстракции. С таким кодом проще работать. Например, IDE может по нажатию клавиши предоставить список всех реализаций заданного интерфейса и мне просто надо выбрать из предложенного.
VE>Я вам про фому, а вы мне про ерёму. Я вроде процитировал фразу, на которую отвечал, чо с темы-то съезжать?
Здравствуйте, Sinclair, Вы писали:
T>>- Даже если в одном месте будет реализация интерфейса с одним методом и без состояния, это сразу делает всю программу функциональной? S>Нет, но это шаг в нужную сторону.
T>>- Если сейчас в интерфейсе один метод и в реализации нет состояния, это еще не значит, что в будущем ничего не изменится. ООП в данном случае предоставит удобную возможность расширения функционала. S>1. Изменение количества методов в ФП достигается очень просто. Нужно два метода — делаем "структуру" из f1() и f2().
"структура" из f1() и f2() — это тоже шаг в сторону ООП. Чем такая структура принципиально отличается от объекта?
S>2. А вот если рисователю рамок потребуется состояние, то это очень крутая смена сигнатуры у функции "рисуйРамку". У этого решения есть крайне тяжёлые последствия — например, теперь мы не можем быть уверены, что перестановка порядка рисования рамок останется корректной.
Мы и раньше не были в этом уверены, так как операция "нарисовать рамку" по определению имеет побочные эффекты.
T>>- "рисователь рамки" — это не просто сигнатура функции, это абстракция, которая олицетворяет собой некоторую ответственность. Вводится разделение между названием абстракции и названием конкретной реализации этой абстракции. С таким кодом проще работать. Например, IDE может по нажатию клавиши предоставить список всех реализаций заданного интерфейса и мне просто надо выбрать из предложенного. S>А зачем смешивать IDE и семантику языка?
А почему нет?
S>Описанное преимущество — это заслуга статической типизации.
Не только.
S>Если она же есть в ФП, то теоретически ничто не мешает мне "по нажатию клавиши" получить список всех функций с заданной сигнатурой.
Какая мне польза от тысяч функций с сигнатурой "void f()", когда я ищу, например, реализацию ITransaction, членом которого (интерфейса) является "void Rollback()"?