Pull to refresh

Comments 137

Почему объектно-ориентированное программирование — это отстой.
А вот не подерётесь, а вот и не будет холивара.
А тут и не должно быть холивора. Это перевод статьи из достаточно далёкого прошлого.
Статья показывает спираль времени, и не более.

А ещё она показывает метастазы лор-синдрома на хабрахабре, где вместо чтения и обдумывания принято писать весёлые комментарии и плюсовать.
Я не вижу смысла коментировать такие статьи с такими «кричащими» заголовками. Беглого прочтения мне достаточно. Да и смысл то, если я не согласен по всем четырём пунктам? Тут, как говорится, «кесарю кесарево».
Я не про вас, я про холивор, ну.
>>лор
>>плюсовать
Ну ты понял. Плюсодрочерство присуще как-раз таки данному ресурсу.
Ведущим аналитикам виднее :)
4 сомнительных доводов против, нет ничего идеального, и я использую ООП потому что доводов «за» куда больше четырех.
А такие доводы можно про все что угодно привести: «Функции отстой, когда появился ассемблер, там были лишь регистры и операторы, больше ничего не нужно, все открыто и понятно! поэтому я считаю что функции — отстой, они слишком группируют код»
Не поверите, но у меня отец примерно такого мнения. Он по образованию инженер-конструктор, ему схемотехника ближе и больше по душе. Поэтому программировать он может исключительно на ассемблере, а обо всём выше уровнем отзывается примерно так вот :)
так всегда было и будет, когда придумали ассемблер, половина говорила что это тормознутое говно и вводить двоичные коды лучше, потом придумали процедурные языки, и половина говорила что ассемблер круто, а процедурные языки — тормознутое говно. И в итоге появилось ооп =)
Думать надо, а не пытаться думать, перед тем как что-либо делаешь. Если руки из сами знаете откуда, то самая лучшие инструменты не помогут.
ну как сказать.

ООП — это порядок. в принципе,
можно писать и на процедурах отличный код.

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

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

да и потом, объект — хорошая абстракция, хороший инструмент. нужно уметь его готовить :)
Поддерживаю! ООП учит декомпозиции, учит уменьшению связности между кусками кода. Да, это не серебряная пуля, но плюсов у такого подхода очень и очень много. Помнится, был в универе у нас Пролог, так к концу семестра отлаживать программы, которые состояли из ~50 правил было уже почти невозможно. У каждого языка своя фича, так вот у Erlang — масштабируемость (эта та, которая меня прям сразила) за счёт функциональности языка. Это его вотчина, не надо туда лезть с ООП, «приделывать ООП к Prolog», ИМХО, глупо и бесполезно.
Прошу прощения, но вы здесь неточны. У эрланга прежде всего масштабируемость за счёт агентской модели (и обмена сообщениями между агентами- как следствия) и хорошей инкапсуляции понятия «адрес процесса». Без FP это сделать вполне реально, в чем-нибудь вроде мозилловского Rust, например.
Понимаете, тут как. Структурное мышление, декомпозиция, системный подход — это всё межотраслевые дисциплины, которые ортогональны программированию (программированию вообще и ООП — в частности) в плане образа мышления.

И(П)П, ООП, ФП, ДП, ЛП — это всего лишь способ записи модели, построенной в голове у программиста.

Учиться структурному мышлению по конкретной парадигме — это как обучаться языку по политическим лозунгам, написанным на нём.

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

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

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

А можно пример, пожалуйста?

P.S. Не холивара ради. Для самообразования. Честно.
UFO just landed and posted this here
Так они и сейчас отстой. У них масса недостатков! Но это совсем не повод сейчас от них отказываться.
Электродвигатели вот по всем параметрам круче, но сколько там десятилетий прошло до тех пор, пока первый более менее успешный электромобиль сделали и сколько еще десятилетий пройдет прежде, чем они доминировать будут?
Всему свое время! Сейчас вот функциональные фишки тоже в мейнстримовые ЯП шагают.
Электродвигатели далеко не по всем параметрам круче. Скорее даже наоборот: при равной мощности и долгоиграбельности (с учётом питания) они очень сильно проигрывают ДВСам по массе и габаритам.
Электродвигатели по всем показателям круче ДВС.
А вопрос питания — это не к двигателям претензии.
Теоретический подход.

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

А там, где жёстко стоит вопрос питания, по совокупности пока что ведут ДВС и ТРД. А иногда даже самые тупые ЖРД!
В карьерных самосвалах как обстоит вопрос с питанием?
Я вас верно понимаю: вы спрашиваете как обстоят дела с питанием в повозке грузоподъёмностью 30-120 тонн?
Хех. По каким параметрам ЭД лучше для повозок грузоподъёмностью 300-1000 кг?
Приёмистость. Высокий момент практически на любых оборотах. Отсутствие коробки передач и потерь энергии, связанных с ней.
Стало быть, вы в курсе и принципиальных недостатков ЭД? ;-)
По сравнению с ДВС это мелочи.
ЭД сам по себе отличный исполнительный механизм. Его слабое распространение связано исключительно с питанием, а не с его недостатками как двигателя.
Так можно сказать про что угодно — например ДВС на водороде тоже очень хороши — мощные, экологически чистые, только вот такой объём водорода на дороге не валяется, но это не проблема движка, ага? :)))
Какой смысл рассматривать движок без питания? Он работает без питания? — нет! Следовательно и сравнивать нужно в комплексе!
Это сфероконь.

Вашими суждениями — гаубица вообще близка к идеальному механизму.
Даже так — фугас как таковой ещё лучше.

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

По «разумно продолжительному времени» отсекается и ЭД, и гаубица, и фугас, и троллейбусы/трамваи, если разговор не идёт о карьерных самосвалах. И только.

Суда ходят на мазутных (дизель-газойльных) ДВС, к слову говоря. А грузоподъёмность ведь в десятки и сотни карьерных самосвалов.
Читнул освежить память.

Дизель-электроходы имеют основным двигателем высокооборотный ДВС и электрическую передачу. Карьерные самосвалы так же являются «дизель-электроходами» с ДВС и электрической передачей.

Так что звезда ЭД как самостоятельного источника энергии блекнет чегой-та.
Caterpillar 797B грузоподъемность 345 тонн. Дизель.
Белазы и liebherr дизель-электрические, питание электроприводов обеспечивается как раз таки за счет ДВС.
Холиварить на тему ЭД vs ДВС можно долго, но пока нет достаточно эффективных аккумуляторов — ДВС будет лидировать. Ну или пока нефть не кончится.
Ну и еще один минус в сторону ЭД — пробой обмотки — довольно таки дорогостоящий ремонт выйдет.
Ничего, аккумуляторы скоро появятся.
Обмотка как раз ремонтируется (если пробой вообще случится). Перемотать обмотку проще, чем менять прогоревшие части ДВС.
Сомнительно что перемотать проще, чем заменить. На самом деле если ремонт осуществлять заменой — то тут оба на равных будут примерною
«Реактивные двигатели делают и те и те, а цистерна топлива рядом, это уже не к двигателям претензии.»
Неудачная аналогия. Если продолжать, можно ещё ионный двигатель привести в пример. Тоже неудачный.
Не убедили. Можно повторить все 4 пункта и сказать, что это достоинства.

Хотя я больше всего люблю Pascal…
> Поскольку функции и структуры данных — это совершенно разные виды животных, то решение содержать их в одной «клетке» фундаментально неверное.

Хммм, я б сказал, что функции — это животные, а структуры данных — это еда для животных, и в каждой клетке безусловно должна присутствовать пища, причём соответствующая. Не стоит кормить корову сырым мясом, а льва — сеном.
Правильно. А наследник — это функция, съевшая в прошлом порцию данных и ставший после этого другим животным. (И вообще правильнее — не наследование, а эволюция. В наследовании стремятся показать эволюцию — такая метафора ближе к сути.)
Читал я оригинал по ссылке с хакерньюс. Не согласился.
Лично я как раз в процессе переписывания своего проекта, который был полностью сделан в процедурном стиле, на ООП.
Разрешите поделиться своими ощущениями.
Конечно, без базового образования крайне сложно перейти от процедурного мышления к ООП. Я очень долго пытался, читал книги и т.п. Но в какой-то момент пришло понимание.
И теперь я делаю проект практически заново, к старому обращаясь только как к справочнику — большая часть кода переписывается.
Зато — ощущение такое, что проект, сделанный по принципам ООП, более логичный и простой в понимании и изменении.
Я в одном месте поменял что-то, раз — и всё работает. И мне не надо держать в голове, или искать каждый раз, откуда какая процедура вызывается, какие там параметры в каком порядке, не надо данные из одной процедуры в другую пихать, и можно ли поменять что-то так, чтобы в другом месте не сломалось…
Преодолев определённый размер, процедурный проект стал лапшой, которую крайне сложно распутывать.
Собственно, ради этого и придумано ООП — части проекта мало связаны меж собой и их проще обновлять и изменять. И это главное преимущество ООП, как я его понимаю — а оно как раз в статье никак не опровергнуто.
Поэтому сейчас я за ООП. А недостатки можно везде найти — подумаешь, откровение какое. Попробуйте предложить что-нибудь другое.
>>Преодолев определённый размер, процедурный проект стал лапшой, которую крайне сложно распутывать
Т.е. по вашему процедурный код в любом случае станет лапшой, а ООП никогда лапшой не станет?
>>ради этого и придумано ООП — части проекта мало связаны меж собой и их проще обновлять и изменять.
Т.е. по вашему декомпозиция в процедурном стиле вообще не доступна?
Я не знаю, почему вы обобщаете мои слова.
Я написал про свой проект и про свои ощущения от него.
Общих заявлений стараюсь не делать.
Лапша возможна и там и там.
Но для ООП существуют методики организации порядка (те же шаблоны проектирования), а для процедурного подхода ничего такого нет кроме интуиции программера.
Хорошо структурированный и написанный код везде хорош, как и в процедурном, так и в ООП.

Иногда я пишу ООП, иногда я пишу процедурами. Это все зависит от размера проекта и дальнейшего обслуживания.
При очень большом объёме проекта, к какому стилю вы будете склоняться — процедурному или ООП?
Зависит от проекта и языка.
Есть такая штука, как модули, блоки и комментарии к коду, которые позволяют разносить проект даже в процедурном программировании
вот только автор статьи противопоставляет ООП и функциональное программирование, а не процедурное ;)
С нетерпением жду, статей, продолжающих цикл: «Почему императивное программирование — отстой», «Почему функциональное программирование — отстой», и завершающей цикл статьи «Почему программирование — отстой».
Страуструп, типичные ошибки при разработке:
24.2.1. Отказ от классов.
24.2.2. Отказ от наследования.
24.2.3. Отказ от статической проверки типов.
24.2.4. Отказ от программирования.
24.2.5. Использование исключительно иерархий классов.
А он там нигде не писал про типичные ошибки в проектировании языков? :)
В статье многовато философии, по моему мнению. А философия плоха тем, что отворачивает взор от практики.

1е возражение — довольно спорно. Если юзается объект, значит у него есть некоторое внутреннее состояние. Внутреннее состояние (в виде структур данных) бесполезно, если оно никак не связано с внешним миром. А связано оно через методы. Так что получается, что структуры данных и функции для работы над ними не являются абсолютно разными вещами, а скорее частями одного целого.

С остальными аргументами более-менее согласен. Вообще приятно видеть, когда возражения против ООП адекватны, а не вытекают из непонимания концепций ООП спорящим (как на знаменитом избиении ООПшников на их же конференции).
Тупой код и умные структуры данных проще в обслуживании и работают стабильнее чем умный код и тупые структуры данных. Пора уже с этим смириться.
А что хачить проще? Хачить проще тупые стуктуры. Для прикладного программирования must have фича :)
Немного эмоционально, но в целом — по делу.
Автор гиперболизирует. Настоящая проблема в том, что универсальные языки — это отстой.

Каждый язык должен занять свою специализированную нишу и тогда будет порядок. То, что функциональные языки можно применять при сайтостроительстве, императивные при создании баз знаний, а логические при автоматизации процессов, как раз все это приводит к хаосу и вечным багам.
Уточните тогда: какие языки, на Ваш взгляд, наилучшим образом годятся для сайтостроения? И также ещё: какою, на Ваш взгляд, является ниша объектно-ориентированных языков?
>> какие языки, на Ваш взгляд, наилучшим образом годятся для сайтостроения

Это очевидно. Те языки, которые изначально для этого создавались (а не приросли библиотеками по мере эволюции). Тот же всеми любимый PHP.

>>И также ещё: какою, на Ваш взгляд, является ниша объектно-ориентированных языков?

Вопрос с подвохом. Ниша очень широкая, так как можно весь мир представить в качестве объектов наделенных методами и свойствами. Но если брать за примеры упомянутые мною сайтостроение и проектирование баз знаний, то писать рабочий код на С++ можно, но затратно по ресурсам — кроме денег уйдет просто банально много времени на «изобретение велосипедов», которые уже есть в специализированных языках.
Автор однобоко подходит к виденью ООП. Дескать, «код и данные вместе», «состояния есть» и т.д. Достаточно чуть более глубоко взглянуть на процесс вызова метода класса, и мы увидим, что сам по себе этот метод никакого состояния не имеет — ему на вход неявно передаётся объект this и вот с этим объектом он все операции и делает. Вот вам и отдельно данные от методов. Не хотите иметь внутренних данных в классе с методами — ну, не создавайте их там. Делайте методы статическими. Храните данные в других структурах. Не храние их вообще нигде — вычисляйте на рантайме и гоняйте между статическими методами. Передавайте туда\сюда делегаты.

ООП даёт возможность быстрее и нагляднее моделировать реальный мир, не углубляясь в дебри логических построений. Это вот как измерить объём воды в стакане. Можно вывести через интегралы формулу объёма цилиндра, а можно взять мерную тару и перелить воду туда.
>Делайте методы статическими. Храните данные в других структурах.

И получите процедурный язык :)
Каким объектам в реальном мире соответствуют фабрики, декораторы, визиторы?
первым двум — линейка сотовых телефонов, с одинаковой печатной платой внутри и разными наборами кнопок и функций.
У вас нарушение в логике.

Если «ООП даёт возможность быстрее и нагляднее моделировать реальный мир», то это ещё не означает, что «ООП может моделировать только реальный мир».
Ничего подобного я не заявлял. И даже привёл обратные примеры.

Мысль в том, что не всё удаётся моделировать объектами один к одному, иногда приходится создавать «нереальные» объекты.
По-моему вы всё-таки не понимаете.

Тот факт, что порой приходится создавать нереальные объекты, никак не опровергает тот факт, что ООП даёт возможность быстрее и нагляднее моделировать реальный мир.
Функциональные, процедурные и объектные языки — на любом из них, при желании, можно писать любой из парадигм. Но ООП превратить в функциональный или процедурный — проще.
ООП по большому счету используется только в создании библиотек. Прикладной код вы наверное сами видели: в основном stateless сервисы, гоняющие классы без поведения (классы, вырожденные в структуры). Иногда сокрытие используется конечно же в прикладном коде, как и наследование. Но все это не критично. Копья тут ломать не обо что.
Зависит от сложности прикладного кода и уровня прокаченности архитектора.
Зависит конечно. Только скорее не от сложности, а от природы. Есть толстые домены, а есть худые. Как пишет Эванс, толстые модели обычно применяются для небольших, но сложных доменов. Для больших и сложных он сам же рекомендует некоторое сочитание ООП и компонентного подхода. На практике такого правда не видел. В huge системах я обычно видел худые модели — из за гибкости (количество багов естественно больше, но лучше как-то написать систему и отладить, чем не написать или писать слишком долго)
Спор ниочем. ООП — это стиль. Смешивать стили программирования — это как заправлять шубу в трусы.
Посмотрите Nemerle, Ruby. В смешивании ничего плохого нет.
Вы же не станете утверждать что Ruby — это функциональный язык. Все базовые вещи там ООП.
Например, длина строки это метод str.length, в Erlang же функция — len(String).
Как-то вы слишком грубо детектите ООПнутость/функциональность языка. В Ruby всё возвращает значение, есть ФВП, можно писать достаточно большие программы без единого разрушающего присваивания.
Вместо того, чтобы приоткрыть состояние и минимизировать его влияние на код,

как раз состояние скрывают, чтобы минимизировать его влияние на код (чтобы состояние вручную не правили)
То, что ООП скрывает состояние — это только дает иллюзию того, что с большим и несвязанным состоянием можно как-то жить. Это только усугубляет проблемы, а не решает их.

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

Яркий контр-пример — MVC в вебе, где вроде как ООП, а стейт — почти весь в базе и каких-то относительно простых и несвязанных между собой кэшах. Объекты если и мутируют, то только для того чтобы составить через это запрос на update в базе, а потом быть выкинутыми. Т.е. MVC — это подход в ФП-стиле. В противовес MVC можно посмотреть на ASP.NET webforms и оценить масштаб боли от ФП-подхода в той же самой задаче.
Это не сложный UI, а кривой. Если не мешать всё в одну кучу, то ничего не моргает.
А на счёт состояния — MVC для этого и придумали, что бы путаницы не было. Правда, его мало кто реализует нормально.
MVC нормально реализуют в вебе, потому что там мало внутреннего стейта и даже с ООП можно как-то более-менее отделить предметную область и функции над ней (модель), контроллер (монадические операции) и view — однонаправленные (в вебе) чистые функции из модели в html.

В дескопных приложениях это сделать трудно потому что классические ООП-языки плохо подходят для реализации своего же самого раскрученного паттерна. В десктопе ООП-библиотеки требуют копирования стейта в их объекты, через это требуется двунаправленная синхронизация этого стейта, которая почти всегда делается тупо руками. Есть датабиндинг, который упрощает это дело, и чем более он развит, тем более это все не ООП, а reactive programming, который гораздо больше уже про ФП.
Всё, что вы описали для веба, верно и для клиентского ООПшного UI. Но правильно этот паттерн мало кто реализует — обычно пишут, как проще — взять и руками поля с данными связать.
Правильно, мало пишут. Потому что геморно, нет нормальных для этого инструментов.
Яркий контр-пример — MVC в вебе

Пример некорректен. В вебе не приживаются stateful-подходы (тот же webforms), потому что сама по себе натура веба (http) — stateless. А вот в толстых клиентах подходы с состоянием как раз прекрасно работают (тот же WPF с его MVVM).

MVC — это подход в ФП-стиле

Это вы говорите сейчас про привычный нам всем mvc в вебе. А настоящий первый MVC — это вполне себе ООП.
Я специально разделил вебовский и обычный MVC, потому что это вообще две разные вещи.

Так вот вебовский прекрасно пашет из-за того что там размазанное ООП-приемами состояние не доживает до краха несогласованности.

А классический MVC, хоть и пытаются делать, нифига не получается. И чем дальше там уходят от ООП в сторону реактивного программирования (тот же WPF-ный датабиндинг) — тем всем становится легче. Это, конечно, обзывают свежепридуманными ООП-терминами, но это дорога в ФП-сторону.
Это, конечно, обзывают свежепридуманными ООП-терминами, но это дорога в ФП-сторону.

Я, если честно, с трудом понимаю, как модель с весьма существенным количеством внутреннего состояния (и перманентными побочными эффектами) можно называть движением в сторону функционального программирования.
В MVVM значимое состояние отделяют от всяких button.TextColor, а состояние UI привязывают декларативно к модели. Это движение в сторону более атомарного стейта, который сложнее рассинхронизовать, и всяких декларативных замутов, усложняющих отстреливание себе конечностей.

Если продолжить в этом направлении еще немного — получится чисто Functional Reactive Programming. Который обзовут как-нибудь типа «LINQ to DataBinding», скажут что сами это все придумали, и продолжат рассказывать какое ФП говно :)
… а я все равно не понимаю, как вы можете говорить о чистом ФП при наличии побочных эффектов (и не просто состояния — а общего разделенного состояния).
А я не говорю о чистом ФП. Я говорю о переползании рожденных в ФП-сообществе подходов в мейнстрим.

Мой поинт в том, что люди говорят что ООП — это круто, тогда как все улучшения ООП-методологии с момента его изобретения заключаются в адаптации ФП-идей и послаблении всяких ООП-шных догм. Что хорошего придумали на основе прекрасной ООП-парадигмы за время ее существования?
Что хорошего придумали на основе прекрасной ООП-парадигмы за время ее существования?

Программирование на основе контрактов.
Роль контрактов в ФП выполняют развитые системы типов. Которые, кстати, реально работают и повсюду применяются.

А вот в ООП я за 7 лет промышленного программирования контракты не видел чтобы применялись.
Роль контрактов в ФП выполняют развитые системы типов.

И вот как развитая система типов определяет, какой набор операций может и должен совершать некий компонент?

А вот в ООП я за 7 лет промышленного программирования контракты не видел чтобы применялись.

Весь SOA, вообще-то. WSDL — это контракт. Даже интерфейс — это контракт.
Интерфейсы — это часть системы типов вообще-то. А wsdl описывает структуру данных, что тоже является частью системы типов.

Но в C# мы даже не можем на уровне системы типов сказать что параметр метода не может быть null. А в Хаскеле — можем. И можем даже написать имеет ли право функция делать IO. А в какой-нибудь AGDA мы даже можем сказать что функция не может возвращать не отсортированный список.

Да, многое чего не хватает системе типов в C#, можно проверить в рантайме. Чем и занимаются всякие контрактные библиотеки. Но это, очевидно, дает гораздо более слабые гарантии.
Интерфейсы — это часть системы типов вообще-то.

И что, в системе типов ФП можно определять операции над типом?

А wsdl описывает структуру данных, что тоже является частью системы типов.

Э нет. WSDL описывает операции как раз.

Но в C# мы даже не можем на уровне системы типов сказать что параметр метода не может быть null.

Это недостаток языка, а не парадигмы. Что успешно доказано наличием большого количества статических анализаторов.
>И что, в системе типов ФП можно определять операции над типом?
Разумеется можно, нужно, и оно именно для этого и сделано.

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

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

А в ФП это все явно, и через это просто. И в этом как раз одна из сильнейших сторон ФП. Пока люди, с переменным успехом, пытаются прикрутить хитрые статические анализаторы для обнаружения null-ов и т.п., в ФП языках оно уже есть из коробки и прекрасно пашет.
Разумеется можно, нужно, и оно именно для этого и сделано.

Можете привести пример, как определить набор операций для конкретного компонента (т.е., не всех операций с типом, а только необходимых компоненту)?

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

Повторяю еще раз: это проблема языка, а не парадигмы. И да, неявные параметры и побочные эффекты — это не объективные недостатки, а вещи, которые не рекомендуются в ФП. И в ФП вообще они прекрасно существуют (я знаю как минимум один язык, где это можно сделать).

Ну и да, например в WSDL можно указать, что передаваемый объект не может быть null.
>Можете привести пример, как определить набор операций для конкретного компонента (т.е., не всех операций с типом, а только необходимых компоненту)?

В Хаскеле это позволяют делать классы типов. В C# и Java — интерфейсы.

>Повторяю еще раз: это проблема языка, а не парадигмы.

Неявные параметры и сайд-эффекты прямо вытекают из императивной парадигмы. А их них уже вытекает сложность статического анализа кода и куча других проблем.

Идея ФП не в том, чтобы запретить стейт и побочные эффекты совсем. Без них ничего не сделать же. Идея в том, чтобы максимально локализовать их, и через это сделать предсказуемыми и управляемыми. Любая ФП-программа имеет императивный кусок, вопрос в его размере.
В Хаскеле это позволяют делать классы типов. В C# и Java — интерфейсы.

Как это делать в ООП-языках, я понимаю. А в ФП? Я бы хотел именно пример увидеть (в идеале, конечно, на F#).
F# я не шарю, но там вроде те же самые интерфейсы что и в остальном дотнете.

В Хаскеле похожая система:

есть тип:
data Person = { name :: String, age :: Integer }

есть классы типов (что-то вроде интерфейсов):
class Eq a where — класс типов, которые можно сравнивать на равенство
equals :: a -> a -> Bool

class (Eq a) => Ord a — класс типов, которые можно сравнивать на больше/меньше (от типа «наследует» Eq)
lessThan :: a -> a -> Bool

Мы можем реализовать Eq для Person:
instance Eq Person where
equals (Person name1 age1) (Person name2 age2) = (name1 == name2 && age1 == age2)

Дальше мы можем требовать в любых операциях, для любых операндов, принадлежность к одному или более классов типов:

printSorted :: (Ord a, Show a) => [a] -> IO() — чтобы напечатать сортированный список, надо его элементы уметь сравнивать и выводить в строку.

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

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

instance Person — сущность, ей можно послать сообщение equals с двумя параметрами и получить ответ. Данных у нее нет, но так бывает вообще.

Наличие инкапсуляции достаточно для объектности языка программирования, но ещё не означает его объектной ориентированности — для этого требуется наличие наследования.

Наследование есть, как мы видим на примере Eq и Ord.

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

Это, очевидно, тоже есть — может быть больше одного instance для одного класса Eq, и они могут иметь разную реализацию.

Так что формально это ООП, и от бытия ТРУ ООП его отделяет только наличие внутренних данных.
Хочешь я тебе точно также докажу что ассемблер — ООП-язык?
Не хочу. Потому и говорю, что это уже не интересно, потому что к содержанию дискуссии отношения особого не имеет.
> Почему объектно-ориентированное программирование — это отстой?

А почему бы вместо того, чтоб 20 лет сотрясать воздух, не взять бы и не написать какую-нибудь вшвенькую 1С-бухгалтерию без объектов, зато на функциональном языке? Или игрушку какую в 3D?
Сразу бы все вопросы отпали, и у тех и у других :)
Почему бы не построить безупречно и безотказно работающую телекоммуникационную платформу на императивном языке с ООП? :)

Наверное потому, что каждому инструменту — своё предназначение. В этом мире даже general-purpose-языки на поверку оказываются достаточно узко заточенными.

Ну и надо делать скидку на то, что те самые 20 лет назад стеки технологий были абсолютно другими, а ООП было на уровне концепций, местами сырых инструментов и нескольких фейлов типа современных Dart и Go.
> Почему бы не построить безупречно и безотказно работающую
> телекоммуникационную платформу на императивном языке с ООП? :)

Если Android — это платформа, а Java — это ООП, то почему бы и нет :)
Потому что а) вы ответили на риторический вопрос, чего делать нельзя; б) вы на него не ответили.
То ответил, то не ответил… Топик, вроде, не про нечёткую логику был ;)
Игрушку? В 3D? На функциях? Да пожалуйста!

old.siteszone.ru/games.html

Все кроме последней 3Dшные написаны на Делфи-движке DGLE, который правда использует кое-где классы (вроде бы внутри него таки есть классы, но я то их не использую!). Пакмэн 3дшный тоже написан без классов.

Так что энто… уточняйте требования ;)
Где-то функциональный подход рулит (алгоритмы обработки потоковых данных к примеру, которые должны хорошо масштабироваться на N тредов и никакого состояния внутри особо не содержать). А есть сложные десктопные приложения, где состояние — это основное, и нужны какие-то абстракции, чтобы хранить это состояние. Не представляю себе WPF, реализованный в функциональном стиле. ООП просто сложнее приготовить правильно (зато проще сделать неправильно), это и приводит к тому, что библиотеки точатся и допиливаются годами, добиваясь смысловой целостности абстракций.
WPF во-первых весьма декларативен (XAML), во-вторых уже сильно ближе к ФП-стилю построения интерфейсов. Скажем развитый data binding — это движение в направлении reactive programming. А reactive programming — это как раз про то, как строить интерфейс в чистом ФП.

Или тот же MVVC-паттерн — это попытка выделить минимально возможное состояние и положить одним куском, не размазывая по коду, что тоже весьма в ФП-духе.

Просто ООП-шники все переназывают своими терминами, через это создается видимость что это ООП развивается и прекрасен. На деле все последние удачные движухи по поводу ООП-архитектур — это в основном перенятие кусочков ФП в ООП-мир.
Что ж в этом плохого? Как раз за гибридными вещами будущее и есть. Никто не будет писать десктопные приложения на чистом функциональном языке. Программистам хочется делать не только функциональные абстракции, но еще и абстракции объектов, хранящих состояние. А уж чего больше в MVC и databinding'ах — ООП или функциональщины — это еще вопрос :) Реактивное программирование, судя по вики, к функциональному программированию не относится и является обособленной парадигмой, которую использует и ООП, и ФП. Выделение минимально необходимого это не есть изобретение ФП, это перифраз бритвы Оккама, методологического принципа, используемого повсеместно.
Ничего плохого нет.

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

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

Рано или поздно какой-нибудь опопсенный хаскель придет даже в enterprise-программирование, но промышленному программированию все равно придется пройти этот путь через гибридные языки.
ООП — не отстой, но и не панацея. ООП — всего лишь способ создания и разделения абстракций. Главные понятия — классы и объекты. Классы бывают двух видов: тип данных и средства обработки/модификации. Объекты — это экземпляры типов данных. ООП — идея о том, что можно написать код и использовать в дальнейшем. Но все учесть невозможно, поэтому и есть скрытое состояние объекта — чтобы программист не мог случайно поломать класс.
> Классы бывают двух видов: тип данных и средства обработки/модификации.

Еще раз: это вырожденный случай ООП (на 90% это процедурное программирование) хоть и вполне мейнстримовый.

> ООП — идея о том, что можно написать код и использовать в дальнейшем.

В том, что вы описали вообще нет никакой идеи по сравнению с процедурным программированием. Хотя процедурное программирование тоже позволяет переиспользование, в этом отношении я согласен.
Эту тему лучше переименуйте так: Почему такие темы на хабре — это отстой?
Потому что 95% пользователей хабрахабра не знают Эрланг и, соответственно, не понимают, что имеет в виду товарищ Армстронг, говоря про описание типов, например.

Потому что 70% пользователей хабрахабра про ФП знают только, что «ну, там есть функции, монады и какое-то каррирование».

Потому что 50% пользователей хабрахабра находятся в состоянии аффекта под воздействием хайпа и всяких баззвордов с серебряными пулями.
Не умешь? Не нравится? Не хочешь? — Не пользуйся!
И да, ваша статистика говно, мистер.
> Мы придумали несколько достаточно нетривиальных ответов, которые бы представляли Erlang типа-объектно-ориентированным языком (для тех, кто больше всего тянет руку с этим вопросом), но при этом и не объектно-ориентированным для тех, кто на самом деле в теме.

При этом те, кто НА САМОМ ДЕЛЕ в теме, прекрасно понимают, что Эрланг — язык именно что объектно-ориентированный.
Эрланг использует свой своебразный ООП только на крупном масштабе, а на мелком он чисто ФП-язык. Такой подход неплохо показывает себя.

Вообще ООП — неплохая парадигма для архитектуры приложения в крупном масштабе.

Есть и другие подходы, когда на крупном масштабе применяются монады, data-flow, reactive programming, message bus-ы, какие-нибудь DSL или еще что-то. Тут на вкус и цвет.

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

Вопрос тут только в том, от чего начинать плясать.

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

Согласен.

> на чистом ФП же нельзя сделать сколько-нибудь сложное приложение.

Не согласен.
На ФП все так или иначе себе стейт, монады, ООП, dataflow, и т.п. Называть ли это чистым ООП потому что оно сделано на чистом ООП — вопрос риторический.
опечатался. «Чистым ФП потому что сделано на чистом ФП» конечно
>> на чистом ФП же нельзя сделать сколько-нибудь сложное приложение.
> Не согласен.

Чистый ФП == отсутствие побочных эффектов вообще. В частности, I/O на идеальном чистом ФП уже невозможно.
Алан Кей не заслужил, чтобы его изобретение называли отстоем.
Извинитесь сейчас же!
Вообще говоря, «отстой» — это смягчение оригинального оборота «something sucks».
Так что мне, например, перед Аланом Кеем точно извиняться не за что.
«Когда я придумал ООП, я точно не имел в виду С++» © Алан Кей

Процессы и сообщения в Erlang'е вполне точно соответсвуют именно ООП Кея
У меня создалось впечатление, что автор статьи программировал в основном разнообразные вычисления и расчёты, где вся мощь ООП действительно не нужна.
Когда вы говорите «вся мощь ООП», что вы имеете ввиду? Для чего вам понадобилась «вся мощь ООП»?
Какая невнимательность, вообще то статью написал создатель языка эрланг, глупо выглядите.
Мне кажется, автор не программировал сколь-нибудь сложных структур данных. Красно-черное дерево это структура или функции, которые заставляют его делать свою работу и не нарушать целостность?
Какая невнимательность, вообще то статью написал создатель языка эрланг, глупо выглядите.
Был неправ, пропустил абзац об авторе.
Впрочем автор эрланга и статьи выглядит не менее глупо, так что на сей счет я не слишком переживаю.
Есть подозрение, что в некоторых пунктах (например в пункте про объявления типов и про популярность ООП) он говорит ООП, а имеет ввиду Java. Кто ж виноват, что не все реализации ООП прекрасны во всех отношениях? Но в конечном счете, джава не единственный ООП-язык.
Кстати, могли бы сказать что-нибудь и по сути. Разделение структуры данных и функций с ним работающих имеет какие-то «бонусы» кроме уязвимости целостности данных?
Да я вообще не программист, но статью прочитал, если хотите знать моё мнение я просто Армстронгу верю больше, я за развитием эрланга слежу давно, мне он просто интересен как технология.
Я правильно понимаю, что в пункте 2 abstime=2012 02 31 24 60 60 является валидной датой?
Да, потому что они не zero-based.
А -то думаю, что меня в сон клонит, когда работаю с объектами! :) Спасибо за статью.
Sign up to leave a comment.

Articles