LINUX.ORG.RU

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


1

0

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

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

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

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

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

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

★★

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

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

? Причём тут?

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

Угу. Для таких вещей в плюсах извращаются вот как:

template <class A> class Animal {
  virtual void copulate(A another_animal) = 0;
};
class Lion : public Animal<Lion> {
  virtual void copulate(Lion another_animal) {...}
};
В жабе всё ещё смешнее:
interface Animal<A extends Animal<A>> {
  void copulate(A another_animal);
}
class Lion implements Animal<Lion> {
  void copulate(Lion another_animal) {...}
}
Всё из-за наследования, будь оно неладно. Не будь наследования - да, можно было бы писать
interface Animal {
  void copulate(Self another_animal);
}
и горя не знать.

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

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

Нифига это не ООП. Ну, посмотри, как фуджеты сделаны - оно, конечно, мёртвенькое, но представление даёт.

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

переход от процедурных языков к ООП можно сравнить с переходом от арифметики к матанализу

Можно и так сказать.

А переход к ФП - это переход уже к функциональному анализу.

делать не массив или таблицу чисел, а массив или таблицу функций, например.

А вот это уже обычно делают в ФП, а не в ООП.

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

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

А тебе не все равно как вычисляется результат [функции], особенно если нет побочных эффектов? Когда же есть побочные эффекты, тогда действительно нужна некоторая упорядоченность действий.

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

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

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

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

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

Да нету никакой «естественной модели». Есть модель у тебя в мозгах.

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

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

Не умножай сущности сверх необходимого.

Что не можешь в своей синтетической модели определиться, какой из объектов играет активную роль?

Да я уже давно определился. Что этот вопрос изначально бессмысленен, и по уму там должно быть

написать(текст, ручка, бумажка)
И всё. Правда, ООП тут ни при чём.

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

Да ты к любой метафоре прикопался бы.

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

писатель.написать(текст, ручка, бумажка)
А стал эмулировать ассемблер на ООП.

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

>он ещё и лучший в мире императивный.
Вот как надоело, что этот старый прикол всерьез воспринимают.
Дерьмовый из хаскеля императивный язык.

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

>ООП виноват в том

Длительное употребление оопиума вызывает зависимость и приводит к жажде применения всё более тяжёлых форм этого средства.

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

> Надо быть дебилом(или троллем), чтобы не понимать(не признавать) причины, по которым CL не в мейнстриме.

Нужно быть дебилом (или троллем), чтобы считать, что CL когда-нибудь станет мэйнстримом.

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

> ты так и не додумался привести пример, с которым спорить было бы значительно сложнее: писатель.написать(текст, ручка, бумажка)

Я почему-то думал, что ты в хороших отношениях с К.О.

А стал эмулировать ассемблер на ООП.


Писатель - stateful объект. У него есть (в некотором смысле) слоты для ручки и для бумаги. Можно производить манипуляции с ними независимо друг от друга и от сосбтвенно акта написания. То блокнот взять, то к стене подойти. То с синей ручкой, то с красной. Причем тут ассемблер?

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

> Не умножай сущности сверх необходимого.

«Сделай настолько просто, насколько это возможно, но не проще.» (c) Эйнштейн

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

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

Чо ты такой толстый?

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

>вследствие конструирования функций посредством композиции.

В чем разница вижу между f(x) = x + y * z и f(x) {float r = mul(y,z); r = add(r, x); return r;}?

Композиция — это то же перечисление последовательности действий, которое описывает «как делать», а не «что надо получить».

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

> Длительное употребление оопиума вызывает зависимость и приводит к жажде применения всё более тяжёлых форм этого средства.

Так с любым инструментом. Люди любят показать «класс» ;) http://demotivation.ru/bhm6ihwppk9ypic.html

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

>А тебе не все равно как вычисляется результат [функции], особенно если нет побочных эффектов?

Еще как не все равно. Был такой язык Sphinx C--. Там, помнится, у операторов не поддерживалось приоритета и выражения вычислялись слева направо, и была огромная разница между x+y*z и y*z+x.

Когда же есть побочные эффекты, тогда действительно нужна некоторая упорядоченность действий.

Капитан Очевидность стремится заметить, что любой ввод-вывод — это побочное действие. И функции ввода-вывода вызывают исключительно ради побочного действия, а не ради получения результата о том, сколько байт было успешно записано/отправлено/получено.

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

Вот как надоело, что этот старый прикол всерьез воспринимают.

Гм. А юмор и ирония у нас теперь видны, только если есть смайлик?

Дерьмовый из хаскеля императивный язык.

Смотря для чего. В плане императивных вещей уж всяко не хуже Лиспа.

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

>Да, и для этого есть композиция функций.

Называй как хочешь, только композиция g*f — это var intermediate = f(x); return g(intermediate). Императивщина в чистом виде.

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

Причем тут ассемблер?

Я уже объяснял, язык скоро отсохнет. То, что ты написал - это ровно та же семантика, что и

PUSH ручка
PUSH бумажка
PUSH текст
CALL написать
Или, если ты настаиваешь на сохранении состояния, то
MOV EAX ручка
MOV EBX бумажка
PUSH текст
CALL написать
Меня интересуют несколько более высокоуровневые конструкции, извини.

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

Капитан Очевидность стремится заметить, что любой ввод-вывод — это побочное действие. И функции ввода-вывода вызывают исключительно ради побочного действия, а не ради получения результата о том, сколько байт было успешно записано/отправлено/получено.

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

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

Называй как хочешь, только композиция g*f — это var intermediate = f(x); return g(intermediate). Императивщина в чистом виде.

Ну, во-1, не обязательно, если есть ленивость.

Во-2, а f(g(x), h(x)) - это тоже var a = g(x); var b = h(x); return f(a, b)? Таки ни фига.

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

> А вот это уже обычно делают в ФП, а не в ООП.

Класс - это и есть таблица методов. Что там в ФП я понятия не имею.

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

Так с любым инструментом

На самом деле так с некоторыми людьми. Другие осознают границы эффективной применимости, и тренируют свои мозги, расширяя пределы того, что для них привычно/естественно/etc-ово.

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

> То, что ты написал - это ровно та же семантика, что и

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

Меня интересуют несколько более высокоуровневые конструкции, извини


Де-факто, из нас двоих ассемблером интересуешься только ты.

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

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

implementation details.

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

А почему ты уверен, что такой отдельный процесс есть?

Де-факто, из нас двоих ассемблером интересуешься только ты.

Не, это ты мне его всё время суёшь. В ООП-обёртке.

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

> Угу, и функций ввода-вывода в нехелловорлдной программе - мизер.

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


Как это? Вы вообще чем занимаетесь? У меня так кажется один сплошный ввод/вывод и именно он представляет основную сложность.

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

> А почему ты уверен, что такой отдельный процесс есть?

Я абстрагировался от implementation details, и не делаю ставок на то, есть такой процесс, или нет. Я просто привожу объект в требуемый контрактом state. Моему коду безразлично, что там внутри у писателя. Так что я смогу быстро дописать необходимую логику, если это понадобится заказчику.

А тебе зачем-то хочется привязать свой код к конкретной реализации писателя. Из аргументов только частичное улучшение compile-time проверок и борьба с мерещащимися призраками ассемблера.

Для меня это вопрос выбора trade-off. А ты, похоже, отвязанный от реализации писателя вариант даже и не рассматриваешь..

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

Как это? Вы вообще чем занимаетесь?

Видеоигру фигачим.

У меня так кажется один сплошный ввод/вывод и именно он представляет основную сложность.

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

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

>Ну, во-1, не обязательно, если есть ленивость.

И как тебе «ленивость» поможет в вычислении результата операции композиции?

Во-2, а f(g(x), h(x)) - это тоже var a = g(x); var b = h(x); return f(a, b)? Таки ни фига.

И почему же? Потому что в хацкиле значение h(x) может не вычисляться?

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

Я абстрагировался от implementation details, и не делаю ставок на то, есть такой процесс, или нет.

Ну-ну. Попробуй ещё не делать ставок на то, есть ли отдельный процесс «поднять руку к блокноту».

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

Не, быстро - это я смогу. А ты вынужден будешь писать три метода там, где реально нужен один. Плюс к тому, ты вообще зачем-то завёл отдельную сущность «писатель».

А ты, похоже, отвязанный от реализации писателя вариант даже и не рассматриваешь..

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

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

Потому что в хацкиле значение h(x) может не вычисляться?

Нет, потому, что функции вполне могут вычисляться и в порядке h-g-f, а не g-h-f.

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

Капитан Очевидность стремится заметить, что любой ввод-вывод — это побочное действие. И функции ввода-вывода вызывают исключительно ради побочного действия, а не ради получения результата о том, сколько байт было успешно записано/отправлено/получено.

Еще один близкий родственник К.О.? Ты не поверишь, но ввод-вывод тоже можно записать через функции, причем лениво и декларативно ;) Собственно, вычисления в монаде IO конструируются именно так. Как эти вычисления запускаются - уже дело десятое.

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

Ты не поверишь, но ввод-вывод тоже можно записать через функции, причем лениво и декларативно ;) Собственно, вычисления в монаде IO конструируются именно так.

Собственно, поэтому я и сказал про «отдельную клетку».

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

ленивость в том смысле, что упорядочен действий не требуется во время конструирования вычисления в монаде IO. Все необходимое обеспечивается композицией и порядком применения функций само по себе.

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

>Нет, потому, что функции вполне могут вычисляться и в порядке h-g-f, а не g-h-f.

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

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

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

> А ты вынужден будешь писать три метода там, где реально нужен один.

С такой логикой, предел совершества, это когда из методов у тебя в программе только функция main() :D

Не, быстро - это я смогу.


Рассказывай сказки. Твой код знает и полагается на то, что процесса подготовки бумаги совершенно точно не существует. Когда такой процесс потребуется добавить, старый код придется выкинуть на помойку или как минимум основательно перепахать. Это во-первых ни разу не быстро, а во-вторых error-prone.

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

>Ты не поверишь, но ввод-вывод тоже можно записать через функции, причем лениво и декларативно

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

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

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

Так блин, об этом я тебе и толкую всё время! Если используется композиция чистых функций - то нам глубоко положить на порядок вычисления аргументов. Соответственно, во что это там превратится - не наше дело, не барское.

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

> правила вычислений аргументов функции описаны четко

Afair, в коде на Си f(g(),h()) не определено, что будет вызвано первым: g() или h()

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

С такой логикой, предел совершества, это когда из методов у тебя в программе только функция main()

Функцию main тоже надо писать.

Твой код знает и полагается на то, что процесса подготовки бумаги совершенно точно не существует.

Нет. Ты же не видел реализацию моего единственного метода? Так откуда же ты знаешь, кто там и на что полагается?

Когда такой процесс потребуется добавить,

Вот когда потребуется - тогда будем думать. А пока не потребовалось - будем делать быстро и правильно.

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

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

Типа IO (), как правило.

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

Собственно, поэтому я и сказал про «отдельную клетку».

Я согласен. Причем, кстати, IO довольно хорошо оптимизирована в ghc. Я пробовал использовать и IO, и MonadIO. Результат отличался в разы. Так что, императивное программирование вполне на уровне (только некий Jon Harrop все не унимается на StackOverflow, но он, хотя бы, окамлист и f#-пист).

dave ★★★★★ ()
Ответ на: комментарий от linuxfan
World print(World world, String str) {
    World newWorld = makeNewWorldWithPrintedStr(world, str);
    return newWorld;
}
Legioner ★★★★★ ()
Ответ на: комментарий от Manhunt

Это и в Си так.

В Си не помню, в плюсах, вроде, так. В Джаве не так, там left-to-right.

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

>Afair, в коде на Си f(g(),h()) не определено, что будет вызвано первым: g() или h()

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

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

Кстати, хочу напомнить на всякий случай, что undefined behaviour означает, что любое предположение заведомо ложно, а любая реализация заведомо правильна.

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

> Вот когда потребуется - тогда будем думать.

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

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