Pull to refresh

Что не так с ООП и ФП

Designing and refactoringООPFunctional Programming
Translation
Original author: Yin Wang
Я не понимаю причины существования бесконечных споров вокруг Объектно-ориентированного (ООП) и Функционального (ФП) программирования. Кажется, что такого рода вещи находятся за пределами человеческого понимая, и о них можно спорить бесконечно. Много лет занимаясь исследованием языков программирования, я увидел четкий ответ, и зачастую я нахожу бессмысленным обсуждение этих вопросов.

Если кратко, то как ООП, так и ФП неэффективны, если доходить в их использовании до крайности. Крайностью в ООП считается идея о том что “все что угодно является объектом” (чистое ОП). Крайностью для ФП можно рассматривать чистые функциональные языки программирования.

Что не так с ООП


Наиболее ошибочным для ООП является само понятие “объекта” и попытка определить что-угодно через него. В конце концов, вы доходите до концепции “все что угодно — это объект”. Но это не так, потому что:

Существуют вещи, которые не являются объектами. Функции не являются объектами.

Вы можете возразить, что в Python или Scala функции являются объектами. В Python любой объект с методом __call__ можно считать функцией. Точно также в Scala, функции — это просто объекты с методом apply. Тем не менее, тщательно поразмышляв над этим, можно заметить несоответствие теории с практикой. Дело в том, что функции являются фундаментальным понятием, в то время как объекты лишь содержат их. Мы пытаемся определить функции как объекты, которые содержат методы __call__ или apply, но сами по себе эти методы уже являются “функциональными объектами”. Python и Scala просто похитили все функции, заключили их в тюрьму “объектов”, пометили как __call__ или apply, и в конце концов назвали это “методами”. Конечно, если обернуть все функции в объекты, появляется возможность обращаться с различными объектами как с функциями, но это еще не значит, что можно утверждать что “функции также являются объектами”.

Большинство ОО-языков также лишены нормальной реализации функций первого порядка. Кульминацией можно считать Java, которая вообще не позволяет передавать функции как данные. Да, вы всегда можете обернуть функции в объекты и назвать их “методами”, но, как я уже говорил, это всего лишь похищение. Отсутствие функции первого порядка является основной причиной того, что существует такое множество "​​шаблонов проектирования" в Java. Но как только у вас есть функции первого порядка, в большинстве таких шаблонов просто нет никакой необходимости.

Что не так с ФП


Подобно ООП, концепция функционального программирования начинает больше вредить, когда вы доходите до крайности, а именно до чистых функциональных языков программирования. Для лучшего понимания было бы не лишним понимать, что называют чистым функциональным языком. Как вариант, вы можете прочесть «What is a Purely Functional Language» авторства Amr Sabry (он был моим консультантом при получении PhD). Если говорить в общем, чистые функциональные языки являются неправильным, потому что:

Существуют вещи, которые не являются чистыми по своей сути. Побочные эффекты очень реальны.

Будучи чистыми, ФП-языки игнорируют возможности и ограничения, которые предоставляет физическая платформа (кремниевые чипы, квантовые чипы, не важно). Вместо этого ФП-языки пытаются заново реализовать окружающий мир, передавая на вход некоторых функций “состояние мира” и получая новое его состояние на выходе. Но существует разница между физическими процессами и их симуляцией. Побочные эффекты — это реальные процессы. Они действительно существуют в природе и являются необходимыми для того, чтобы эффективно производить вычисления. Попытка же имитировать побочные эффекты на основе чистых функций обречена быть не эффективной, сложной и скорее всего уродливой. Замечали ли вы, как легко реализовать на С кольцевую структуру данных или генератор случайных чисел? То же самое нельзя сказать о Haskell.

Кроме того, программирование на чистых функциональных языках требует огромных умственных усилий. Если вы посмотрите глубже, то поймете что монады делают программы переусложненными и трудными для написания, а монадные трансформации являются просто уродливыми хаками. Все это очень похоже на “шаблоны проектирования” в Java. Вы заметили, как много тривиальных задач для других языков программирования становиться исследовательской проблемой при попытке реализовать их на Haskell? Постоянно выходят статьи с названием в стиле “Монадный подход к решению такой-то-уже-решенной-задачи”. Иронично, но Amr Sabry (мой консультант в PhD) является со-автором одной из таких статей. Он пытался реализовать семейство языков miniKanren Дэна Фридмена, но так и не смог понять, каким образом сконструировать монады. Он попросил помощи у Олега Киселева, человека, который возможно лучше всех разбирается в системе типов Haskell. И, если вы не знаете, Amr Sabry, вероятно, самый осведомленный в мире человек по теме чистых функциональных языков программирования. Они стали соавторами целой статьи после того, как с помощью Олега, им все-таки удалось реализовать желаемое. Ирония в том, что у Дена Фридмана не возникло вообще никаких проблем с реализацией этого куска кода на Scheme.

Некоторые люди утверждают, что значение монад в том, что они “ограждают” разработчиков от побочных эффектов. Но какой был бы толк от этого ограждения, если бы монады не делали ваш код более понятным или безопасным? А правда в том, что они не делают. Программы, написанные с применением монад так же сложно анализировать, как если бы они были напичканы побочными эффектами. Нет ничего такого, что можно сделать проще с помощью монад, и что не может быть сделано путем статического анализа. Любой исследователь статического анализа знает об этом. По существу, статические анализаторы кода основаны целиком на монадах, и тем самым они отбирают у программистов бремя по написанию монадического кода, вместо того, чтобы перекладывать его на них. Конечно, злоупотребление побочными эффектами делает программный код сложным для анализа, но с другой стороны никто не мешает вам писать чистые функции даже на С:

int f(int x) {
    int y = 0;
    int z = 0;
    y = 2 * x;
    z = y + 1;
    return z / 3;
} 

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

Оглядываясь назад в историю, становится понятным, что именно идеализм математиков стал движущей силой чистых функциональных языков программирования. Математические функции просты и красивы, но к сожалению они работают хорошо только тогда, когда вы пытаетесь моделировать процессы чистые по своей сути. В противном случае они становятся уродливыми. Не стоит бояться умных словечек вроде “Теория категорий”. Я знаю значительное количество различных теорий с таким названием. Даже исследователи теорий категорий порой называют их “абстрактной чепухой”, потому что по сути они занимаются лишь тем, что находят очередной нелепый способ сказать о том, что вы уже и так знаете! Если вы прочтете статью Готлоба Фреге “Function and concept”, то будете удивлены тому, как большинство математиков использовали функции неправильно, и это было всего лишь чуть более столетия назад. На самом деле, математики совершили много плохих вещей со своим языком, особенно в том, что касается вычислений. Так что не существует никаких оснований в том, что проектировщики языков программирования должны слепо учиться этому у математиков.

Не нужно влюбляться в ваши модели


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

Не подгоняйте весь мир под ваши модели. Приспосабливайте ваши модели для окружающего мира.
Tags:фпоопхоливарhaskelljavaфункции первого порядкапобочные эффектышаблоны проектирования
Hubs: Designing and refactoring ООP Functional Programming
Total votes 148: ↑116 and ↓32+84
Views69K

Popular right now