LINUX.ORG.RU

[philosophy] В чем заключается революционность перехода от функциональщины к ООП?


1

0

Так уж повелось, что первый язык, который я изучал, был делфи. Потом всякие сишарпики, С++, лисп, и т.п. В итоге, как мне кажется, у меня ООП головного мозга. Когда возникала задача писать на С, я начал реализовавывать обьектную модель в этом языке.

«Стоп», сказал я себе и подумал. Почему сейчас все кругом вопят про ООП и про его архиполезность и архиправильность? Далее, по ходу раздумий, пришел к мысли, что все, что пишется с использованием ООПшной парадигмы, может быть написано и без нее.

Почему появились языки, которые взяли ООП за главенствующую идею (java, c#, етц)?

Неужели те преимущества, которые предлагает ООП (полиморфизм, инкапсуляция, наследование), дают прирост в эффективности, скорости написания программ, понимания их работы и поддержке? Здесь было бы интересно сравнить одну и ту же программу, написанную на С и на С++, чтобы узреть принципиальные архитектурные различия (может такие уже есть?).

Сухой остаток. ООП представляет из себя еще один уровень абстракции, который позволяет оперировать про проектировании не функциями, а обьектами. А неужели это так меняет дело и делает разработку более удобной?

Было бы интересно без срачей услышать компетентное мнение.

★★

Ответ на: комментарий от www_linux_org_ru

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

паттерн adapter. в Haskell ты в любой момент можешь объявить тип инстансом класса типов, и никаких дополнительных телодвижений это не потребует; в C++ тебе придётся оборачивать объект в адаптирующий его к нужному интерфейсу. сойдёт за пример?

jtootf ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

>> Функционально-ленивое железо никто терпеть не стал бы.

а почему?

Потому что железо должно быть точно предсказуемым.

море возможностей распараллеливания

Реализуется другим уровнем абстракции (от транспьютерных систем до многоядерных).

tailgunner ★★★★★ ()
Ответ на: комментарий от jtootf

> не понял. поясни. лучше, если на примере тех же IWidgets

Iwidgets - это вообще классическое ООП. Виджеты реализованы как классы с наследованием и всеми прелестями. Методы виджетов в виде субкомманд - что это, если не виртуальные функции?

anonymous ()
Ответ на: комментарий от jtootf

>> допустим, мы пишем autocad, но аксиоматика пространства, в котором он будет работать, пока не известна

что мы тогда пишем?

ок, точнее было бы «пока известна не полностью», например, известны все аксиомы, кроме 5-го постулата евклида — который может определиться (а может нет) в процессе разработки и эксплуатации :-)

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от SV0L0CH

Очевидно он осознал разницу между «функциональный» и «чисто функциональный».

Чисто функциональный я вообще знаю только один, при этом он ещё и лучший в мире императивный.

Про языки типа Лиспа и Питона я привык говорить «с функциональным ароматизатором, идентичным натуральному». Ну то есть - химическая дрянь вместо натурпродукта, но попробуй ткнуть пальцем в отличия.

Miguel ★★★★★ ()
Ответ на: комментарий от anonymous

Методы виджетов в виде субкомманд - что это, если не виртуальные функции?

ещё раз - где там позднее связывание? где тип, который определяется в рантайм, и по которому производится выбор кода на выполнение?

если я работаю с IWidget'ом, то у меня никогда не возникает ситуации вида «я работаю с объектом через интерфейс, но кто именно его реализует - я не знаю». если ты можешь показать, как этого можно добиться - прошу

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

> взять что-нибудь проще пространства - полугруппу, скажем,- как ты предлагаешь доказывать замкнутость и ассоциативность для типа, заявленного инстансом полугруппы?

доказывать в общем случае должен программист; а компилятор должен хотя бы хватать на лету то, что очевидно — например, то что операция конкатенации ассоциативна; если у компилятора не получается, то доказывать придется программисту

ну и речь в общем-то не об этом была — речь о том, что язык программирования, заставляющий корежить модель предметной области для того, чтобы *компилятору* было удобнее проверять ограничения, выраженные типами — неполноценен.

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от Miguel

> Про языки типа Лиспа и Питона я привык говорить «с функциональным ароматизатором, идентичным натуральному». Ну то есть - химическая дрянь вместо натурпродукта, но попробуй ткнуть пальцем в отличия.

А в чем проблема? Тыкай в дозволенную по умолчанию мутабельность, от которой хрен избавишься.

tailgunner ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

прекрати бредить — твоя модель ничем принципиально не лучше модели Manhunt-а;

Прости, но вопрос поставил я и возможные решения тоже привёл я.

более того, твоя модель хуже тем, что она подогнана под ограничения конкретных языков

?????

Вообще-то, весь вопрос был о том, насколько естественно представление мира в виде объектов. Ясен пень, Хаскель с Фортом идут лесом, таща за собой упирающийся Тикль.

Miguel ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

доказывать в общем случае должен программист; а компилятор должен хотя бы хватать на лету то, что очевидно — например, то что операция конкатенации ассоциативна; если у компилятора не получается, то доказывать придется программисту

какой смысл в языках, которые всю работу перекладывают на программиста?

ну и речь в общем-то не об этом была

я отвлечённый вопрос задал - тема близка и интересна

язык программирования, заставляющий корежить модель предметной области для того, чтобы *компилятору* было удобнее проверять ограничения, выраженные типами — неполноценен

а с этим я вполне согласен

jtootf ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

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

Ты не понял. Классы Хаскеля не предлагаются в качестве замены C++-ООП.

Miguel ★★★★★ ()
Ответ на: комментарий от tailgunner

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

Ну, я не готов OCaml исключить из функциональных, а там эта самая мутабельность одной буквой задаётся. Да и не в ней дело, в общем-то.

Собственно, ФП состоит из одной технической детали (до которой, в общем-то, и насквозь императивные языки тоже дошли) и стиля программирования. По сути, такое же отличие, как и в ООП vs. процедурщина - одна техническая деталь плюс стиль программирования.

Miguel ★★★★★ ()
Ответ на: комментарий от tailgunner

> Реализуется другим уровнем абстракции (от транспьютерных систем до многоядерных).

да? а что если у нас есть парочка команд mov, одна пишет в память, другая читает, и компилятору известно, что адреса в памяти ТОЧНО разные; железка же до этого вряд ли догадается, пока адреса не вычислит, а еще может и такт потеряет на их сравнение

вообще лень в железе вряд ли нужно терпеть... а вот функциональность я бы хотел — чтобы были такие вот префиксы типа «делай параллельно, адреса точно разные»

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от jtootf

какой смысл в языках, которые всю работу перекладывают на программиста?

Ну, это надо почётного и понечётного штангиста спрашивать. Он у нас основной пропагандист языков с зависимыми типами (в которых доказывать, как правило, приходится практически руками и много).

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

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

Ну, я не готов OCaml исключить из функциональных

Он гибридный.

там эта самая мутабельность одной буквой задаётся

Не тремя (ref)?

Собственно, ФП состоит из одной технической детали

Которую ты знаешь, но не скажешь? :D

tailgunner ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

чтобы были такие вот префиксы типа «делай параллельно, адреса точно разные»

Гм. Сразу на ум приходит DDC с его эффект-инференсом, земля ему пухом, и Microsoft Vault (эх, такой проект пропадает, чтоб им исходники открыть).

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

Ну, это надо почётного и понечётного штангиста спрашивать

уж увольте. читать я его читаю, но общаться с ним - удовольствие заметно ниже среднего

jtootf ★★★★★ ()
Ответ на: комментарий от tailgunner

Не тремя (ref)?

Упс, со Скалой попутал.

Которую ты знаешь, но не скажешь? :D

Так давно сказал. Параметрический полиморфизм. Но это уже даже в Джаве, пусть ущербное по всем параметрам, но есть.

Miguel ★★★★★ ()
Ответ на: комментарий от jtootf

но общаться с ним - удовольствие заметно ниже среднего

Что есть, то есть. Не слишком вменяемый товарисч.

Miguel ★★★★★ ()
Ответ на: комментарий от jtootf

> ещё раз - где там позднее связывание? где тип, который определяется в рантайм, и по которому производится выбор кода на выполнение?

Тип определяется классом виджета. В рантайме происходит диспетчеризация твоих сообщений объекту. Необходимый код может находиться где угодно. Команда, представляющая объект как раз и занимается его поиском через дерево наследования или цепочки делегирования. На неймспейсах легко написать собственную маленькую объектную систему со своим _рантайм_ диспетчером, да ты и сам в курсе наверняка.

если я работаю с IWidget'ом, то у меня никогда не возникает ситуации вида «я работаю с объектом через интерфейс, но кто именно его реализует - я не знаю».

Именно что не знаешь. Ты посылаешь объекту-команде сообщения, а как они диспетчеризуются ты знать не можешь, пока не подсмотришь в реализации. По-моему ты просто пытаешься доказать, что раз объекты в тикле реализуются в виде команд, то и позднего связывания быть не может, мы же всегда знаем точно «адрес» команды. Это так. Но не для субкоманд. Они могут быть обычными процедурами, а могут виртуальными как в объектных системах.

anonymous ()
Ответ на: комментарий от Miguel

> Параметрический полиморфизм.

Хм. Я, конечно, ни разу не практик ФП, но главная отличительная черта, которую я в нем вижу - это именно немутабельность. Всё остальное - HOF, pattern matching, type inference - это просто приятные вещи, на стиль программирования влияющие мало.

И кстати, про окамль и мутабельность - там мутабельность не является режимом по умолчанию, и ее надо специально выбирать.

tailgunner ★★★★★ ()
Ответ на: комментарий от Miguel

> Прости, но вопрос поставил я и возможные решения тоже привёл я.

даже если в начале «написать» было атомарно, то в процессе эволюции программы и требований заказчика может выясниться, что «написать» стало неатомарно

вообще эта дискуссия очень интересная, т.к. тут сталкиваются инженерный и академический подход; видимо, мне стоит написать побольше на эту тему

кстати, имхо vault как раз писали для того, чтобы тайпческать код в стиле манханта

Вообще-то, весь вопрос был о том, насколько естественно представление мира в виде объектов.

весьма естественно

1. стандартный подход к описанию мира — идентичность, объекты и их составные части; у тебя есть иной подход?

2. выделение общих черт в объектах, которое, вероятно, в ООП пошло криво — иерерхически, когда более правильно что-то по типу реляционного

Ясен пень, Хаскель с Фортом идут лесом, таща за собой упирающийся Тикль.

не распарсил

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от tailgunner

главная отличительная черта, которую я в нем вижу - это именно немутабельность.

На мой взгляд, с немутабельностью просто проще писать в этом стиле. Не отвлекает, не нужно думать о лишних сайд-эффектах... приятно. Ну и, плюс, когда пишешь в стиле ФП, мутабельность становится как-то не нужна.

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

> Ну, вообще-то, написать, я думаю, вполне можно, даже с нуля. Правда вот откомпилить это дело и распространять бинарник - таки фиг.

написать параметрически полиморфную функцию через void*, обернуть ее в шаблон, шаблон вытащить в хедер, функцию положить в либу — и нет проблем

т.е. реально, но не очень красиво

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от Miguel

> Остаётся полиморфизм, причём - только ad-hoc, другого в ООП нет.

это в академических ООП-языках;

в с++ же есть void*, через которого хотя бы некоторый параметрический полиморфизм достигается

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

даже если в начале «написать» было атомарно, то в процессе эволюции программы и требований заказчика может выясниться, что «написать» стало неатомарно

Вот тогда и будут написаны соответствующие методы. А скорее - изобретены какие-то более другие абстракции. А то воспроизведение ассемблера мне лично не нравится.

кстати, имхо vault как раз писали для того, чтобы тайпческать код в стиле манханта

Кстати, да, очень похоже. В принципе, будь Vault хоть чуть-чуть пригоден к работе, я бы его юзал.

весьма естественно

Опять начинается...

стандартный подход к описанию мира — идентичность, объекты и их составные части; у тебя есть иной подход?

В каком смысле «стандартный»? Промышленный стандарт? Ну да. Лучше он от этого не становится.

Или в смысле «наиболее соответствующий»? Так ни фига, если моделировать объекты реального мира, то код будет говно даже по ООП-шным меркам. Поэтому очень быстро начинаются адаптеры-визиторы-фабрики, и ничего похожего на «реальный мир» в коде уже не просматривается.

выделение общих черт в объектах, которое, вероятно, в ООП пошло криво

А говоришь, «весьма естественно».

не распарсил

Если изначально обсуждается ООП, то Хаскель, Форт и даже Тикль - не при делах. Не имеют отношения к теме.

Miguel ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

написать параметрически полиморфную функцию через void*, обернуть ее в шаблон, шаблон вытащить в хедер, функцию положить в либу — и нет проблем

Бррр. Да там в любом случае непосредственно кода - чуть, самое интересное будет как раз в шаблоне.

Miguel ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

в с++ же есть void*, через которого хотя бы некоторый параметрический полиморфизм достигается

Самому не смешно?

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

>> стандартный подход к описанию мира — идентичность, объекты и их составные части; у тебя есть иной подход?

В каком смысле «стандартный»? Промышленный стандарт? Ну да. Лучше он от этого не становится.

Или в смысле «наиболее соответствующий»? Так ни фига, если моделировать объекты реального мира, то код будет говно даже по ООП-шным меркам. Поэтому очень быстро начинаются адаптеры-визиторы-фабрики, и ничего похожего на «реальный мир» в коде уже не просматривается.

визитор — это следствие отсутствия должной поддержки в ООП полиморфизма, а не следствие неправильного подхода к описанию мира

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

визитор — это следствие отсутствия должной поддержки в ООП полиморфизма, а не следствие неправильного подхода к описанию мира

Ну, вообще-то, визитор - это не для полиморфизма, а для паттерн-матчинга. Но это только один из паттернов GoF.

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

> Самому не смешно?

нет

и в той задачке (эмуляция зависимых типов на яве-хаскеле) я не юзал void* только потому, что задачка сама по себе бессмысленна, а вот попытки ее красиво решить — интересны

кстати, если хаскельное ее решение выглядит прочно, то решение на яве весьма подозрительно — т.е. может оказаться, что добавление нового кода его *сломает*

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от Miguel

> Ну, вообще-то, визитор - это не для полиморфизма, а для паттерн-матчинга.

а паттерн-матчинг для полиморфизма, нет?

Но это только один из паттернов GoF.

ну да, остальные, вероятно, тоже нужны из-за ограниченности полиморфизма, а не из-за неправильного подхода к описанию мира

рассмотрим самое элементарное ограничение полиморфизма в ООП:

struct Animal { virtual void copulate(??? another_animal) {...} };

где тут проблемы объектной модели/философии? ведь можно написать:

struct Animal { virtual void copulate(this.Type another_animal) {...} };

и все объектно, хотя это уже не с++.

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от Miguel

> Напрасно. Если типобезопасность не обеспечивается, то о ПП речи вообще нет. Неинтересно.

ключевой вопрос — ГДЕ не обеспечивается? в 10 строчках библиотеки или (потенциально) 10 000 000 строчках клиента? это разные вещи

видимо, мне стоит написть mapcar

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от anonymous

Но не для субкоманд. Они могут быть обычными процедурами, а могут виртуальными как в объектных системах.

можно пример? минимальный кусочек исходников, демонстрирующий эту мысль

jtootf ★★★★★ ()
Ответ на: комментарий от dizza

>Особенно ООП сложно реализовать в приложениях работающих с БД (оргнанизация логики крутится в основном вокруг выполнения транзакционных процедур), в распределенных приложениях (удаленный вызов _процедур_, будь он хоть rest, хоть что, все равно вокруг процедур крутится), сильно ограничено применение ООП в многотредовых приложениях.


Ну так надо больше читать о EJB, я считаю, чтобы такую хню не пороть понапрасну.

iZEN ★★★★★ ()
Ответ на: комментарий от Quasar

Современные микросхемы нигде не уступают лампочкам, а тем более транзисторам.

Уступают, и очень сильно. Подсказка: не музыкальная область, а вполне промышленная.

Хотя бы намекни. А то мне моя рабочая специальность на теоретическом уровне как-то не даёт сомневаться. Вот, магнетроны, пока не заменяемы на твердотельную электронику.

iZEN ★★★★★ ()
Ответ на: комментарий от jtootf

иными словами, неиспользуемый код накапливается слоями палеонтологического говна

Именно! Из Java вон как трудно, практически невозможно выбросить старый код. Однако, тела методов могут быть переделаны и с успехом переписываются, а вот сами объявления (публичные интерфейсы классов) — нет. Палеонтология началась с AWT.

iZEN ★★★★★ ()

Объектная модель напрямую возникает в некоторых практических задачах.

Например, GUI: как ты его ни пиши, ты вынужден каждому компоненту сопоставлять экземпляр структуры, плюс функции show hide setsize etc. – вот тебе и ООП.

Другой пример: вычисление БПФ что в FFTW, что в IMKL выглядит примерно так:

hFFT = fft_init(...);
fft_compute(hFFT, InputBuffer, OutputBuffer);
fft_destroy(hFFT);

что, по большому счету, с точностью до синтаксического сахара эквивалентно

Fft fft(...);
fft.compute(InputBuffer, OutputBuffer);
// деструктор сам вызовется

И да, ты вроде путаешь функциональщину с процедурщиной.

anonymous ()
Ответ на: комментарий от anonymous

Например, GUI: как ты его ни пиши, ты вынужден каждому компоненту сопоставлять экземпляр структуры, плюс функции show hide setsize etc. – вот тебе и ООП

вот только это не ООП ни разу

jtootf ★★★★★ ()
Ответ на: комментарий от anonymous

И да, ты вроде путаешь функциональщину с процедурщиной.

а ты путаешь объектно-ориентированный подход с объектно-базированным; то, что ты нарисовал выше - банальное замыкание контекста

jtootf ★★★★★ ()
Ответ на: комментарий от dave

>Функциональный стиль действительно близок к декларативщине. :)

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

Собственно, статья в вики так и говорит, что Functional = Imperative - side effect. С чего вдруг функциональный подход у нас стал близким к декларативному программированию?

linuxfan ()
Ответ на: комментарий от jtootf

> вот только это не ООП ни разу

Ну да, это предпосылка к его возникновению. Уж коль скоро мы вынуждены иметь дело с объектами, там и вся концепция ООП постепенно сама собой выстраивается.

anonymous ()
Ответ на: комментарий от linuxfan

С чего вдруг функциональный подход у нас стал близким к декларативному программированию?

вследствие конструирования функций посредством композиции. вместо описания шагов выполнения последовательно строим сложные функции из простых

jtootf ★★★★★ ()
Ответ на: комментарий от anonymous

Уж коль скоро мы вынуждены иметь дело с объектами, там и вся концепция ООП постепенно сама собой выстраивается.

не, ни разу. то, что у тебя там нарисовано, присутствует в любом языке, поддерживающем абстракцию данных

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

Мой тезис в том, что возникновение ООП обусловлено особенностями практических задач, и как следствие – это оптимальная концепция для достаточно широого класса задач. Это было ответ на вопрос ТС.

Мой пример иллюстрирует необходимость объектов как таковых. Но, придумав объекты, уже нельзя было потом не придумать наследование и виртуальные методы. Хотя «придумать» не совсем то слово, тут жизнь в возникающих перед нами задачами всё придумала.

anonymous ()
Ответ на: комментарий от anonymous

Но, придумав объекты, уже нельзя было потом не придумать наследование и виртуальные методы

таки аргументация вот этой мысли будет?

jtootf ★★★★★ ()

Вы путаете процедурное программирование и функциональное. Функциональное - это совсем из другой оперы.

Nxx ★★★★★ ()

Появление ООП стало необходимо прежде всего, когда появился оконный интерфейс.

Во-первых, это разлизация различных окон и виджетов, которые могут друг от друга немного отличаться - они создаются путем наследования классов.

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

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

Nxx ★★★★★ ()

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

Nxx ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.