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

в 19:04, , рубрики: Программирование, функциональное программирование, языки программирования, метки: ,

На самом деле, в каком-то смысле, этот вопрос не имеет смысл в 2010х, когда большинство (или большинство самых распространенных) языков являются языками многих парадигм. Зачем себя ограничивать только функциональным программированием? Возможно, кому-то ответ покажется очевидным, но если появляются такие статьи как "Десять причин не использовать статически типизированный функциональный язык программирования", то придется дискутировать и объяснять противную точку зрения. «Десять причин...» основаны на иронии и, похоже, автор подразумевает, что упомянутые недостатки даже не требуют обсуждения, а только ироничных замечаний. Но это не так, давайте пройдемся по этим десяти причинам.

Причина 1. Я не хочу следовать последним тенденциям

Самая смешная причина. А, собственно говоря, почему я должен следовать тенденциям? И каким именно? Многопоточность для некоторых стала открытием в 2000х (хотя сама проблема существовала и раньше) и вроде бы должна была стать тенденцией. Но некоторые так до сих пор почти с ней и не сталкивались. Не потому, что они не «модные» (т.е. в тренде) программисты, просто не было задач таких: либо однопользовательское приложение, либо контейнер следил за ней. А кто-то не успел оседлать Веб-программирование, кто-то не успел следовать за мобильными разработками. Можете ли вы как разработчик успеть за всеми тенденциями сразу? Можете, но у вас есть выбор: либо нахвататься по верхам, либо углубиться в одну тему. Или быть посередине. Но не всё одновременно. Возможно, имелось ввиду, что функциональный подход настолько фундаментален, что любой программист должен знать о нем. Это уже более похоже на истину, но не надо аппелировать к тенденциям.

Впрочем, так ли уж эта тенденция настолько важна? И можно ли кого-то убедить, что «новый модный язык скоро завоюет мир»? Возможно, это для кого-то станет откровением, но синтаксис или стиль языка редко были основанием для распространения или популярности. Возможно в 60-80х, когда различные стили программирования только появлялись, но не сейчас. Давайте изучим список наиболее распространенных (популярных) языков на данный момент:

C/C++ — Хотя оба своей популярностью должны быть благодарны синтаксису, но это дело уже далекого прошлого. Да, синтаксис С позволял писать более компактный код (но в отличие от доводов в пользу функционального языка, он предоставлял более краткое выражение для тех же конструкций языка, что и существовали ранее, а не убирал их вообще). Да, синтаксис C++ в каком-то смысле, был «синтаксическим сахаром» поверх C, что возмущало адептов С и долгое время велись споры, о производительности С против С++. Но, в конце концов, эта пара языков до сих пор жива, потому что было создано множество компиляторов под всевозможные платформы, и они являются естественным выбор для любого, кому важна производительность, в первую очередь, так как на выходе получаем исполняемый файл.

Objective-C — Популярность основана на привязке к платформе Apple.

Java — Практически минимум нового синтаксиса по сравнению с С++, но «написано однажды, запустится везде» (и, да, это работает). Плюс апплеты (которые, в конце концов, провалились, но которые были предвестниками Flash и HTML5). Плюс мобильные разработки (т.к. нужен был язык с переносимостью для очень разных телефонов). К тому же, нашел нишу на сервер-сайде и ентерпрайзе.

C# — Еще один клон С++, весь «сахар» появился уже позже, а распространенность основывается на привязке к Windows. Mono? А вы уверены, что когда-либо будет достигнута задача запуска абсолютно любой программы, написанной на С#? И это учитывая, что .Net развивается со своей скоростью, а Mono всё пытается угнаться. К тому же, многие библиотеки очень уж завязаны на Windows.

PHP/Ruby — Два языка, которые завязаны на Веб-разработке. Многим не понравится, что они в одной паре, но это суровая правда жизни. А, кстати, нелюбовь к PHP среди определенного количества программистов объясняется именно «плохим» синтаксисом языка. Что не мешает ему быть популярнее любого функционального языка. Хотя, как ни парадоксально, но PHP стал популярным именно благодаря «простому» синтаксису и быстрой разработке Веб-приложений.

JavaScript — Еще один язык с привязкой к Вебу, но уже на стороне браузера. И с котором, хочешь — не хочешь, должен быть знаком почти любой Веб-разработчик. А ведь в нем есть просчеты «по дизайну». И ничего, живет. Более того, за последние годы, он начал даже жить вне браузера и быть самостоятельным языком. А что? Чем он хуже Python-а?

Python/Perl — Два языка, которые изначально были и «скриптовыми» (как альтернатива Shell языкам) и Веб-ориентированными. Но, постепенно, Perl начал отмирать, именно благодаря своему более краткому и порой эзотерическому синтаксису. Подумайте над этим. Есть все же какой-то предел краткости синтаксиса.

Visual Basic — Привязка к Windows/Office платформе.

Shell — Привязка к Unix.

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

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

Причина 2. Мне платят за строки кода

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

Если же говорить серьезно, то, что такое «строки кода»? Например, у меня есть приложение с 100 строчками кода, я нашел библиотеку, которая сократила их до 5. И никакого функционального программирования. А возможно я нашел даже еще 5 библиотек, которые делают то же самое и сокращают код до 3, 7, 10, 15 и 8 строчек кода. Выбирать ли самую краткую или которая имеет лучшую поддержку, больше опций, обеспечивает лучшую производительность и т.п.?

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

Во многих случаях краткость и понятность кода — это полярные понятия. Чем короче код, тем он непонятнее, и чем более явно всё прописано, тем понятнее. Хотя бывает и наоборот. А возможен ли одновременно краткий и понятный код? Смотря что вы имеете ввиду. Посмотрите на естественный язык. Можно ли в одной фразе выразить смысл романа? Наверное, можно, только смешно выйдет. Можно ли причастный оборот заменить глаголом или другой конструкцией? Конечно, можно, но это вопрос стиля — и у вас всегда есть выбор в естественном языке.

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

Причина 3. Я люблю фигурные скобки

Удивлен такому «серьезному» аргументу. Если вы работаете довольно долго с языком, то вы автоматически ставите все скобки, а часто и сам редактор делает это за вас. Так какая разница есть они или нет? Более того, многие уверены, что даже в однострочном блоке кода (после условия или итерации) надо ставить фигурные скобки, чтобы было явно видны границы блока и чтобы меньше было ошибок, когда код вставляют не в тот блок.

Причина 4. Я люблю видеть явные типы

Я не люблю видеть явные типы, но я люблю, что компилятор видит явные типы. Я не хочу, чтобы он терял контроль над типами. Это защищает меня во многих ситуациях. Но, конечно же, красиво, когда типы неявные и все как-то работает за сценой. Но цена красоты: потеря контроля за тем, как именно это всё работает. А во многих случаях, цена красоты — производительность и неявные операции. И, да, я хочу видеть, что мне вернет метод из библиотеки, которую писал не я, или скажем даже тип выражения, который включает переменные объявленные где-то в других местах программы. Я не хочу гадать будет ли это строка или список объектов.

Причина 5. Я люблю исправлять баги

Причина 6. Я живу в отладчике

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

— нет нулл-ов (решается статическим анализом кода)
— неизменяемые данные (доступно во всех языках программирования, но данный подход не всегда можно использовать, особенно, если дело касается производительности и проблем распределения памяти)
— очень строгая система типов («очень» уже субъективное слово, поэтому этот аргумент оставляем на совести авторов)
— композиция маленьких функций (лямбда функции уже есть в C# и других языках, скоро будут в Java)
— абстракции асинхронного программирования (это вопрос только абстракции, все можно сделать при помощи библиотеки)
— функции высшего порядка для коллекций (есть в C# и других языках, и будет в Java)
— единицы измерения (справедливо для F#, не применимо ко всем задачам)
— порядок операций явно выражен в коде (не проблема использовать в любом языке программирования, но в нём у нас будет выбор использовать данный подход или нет)

Почему-то все ошибки здесь сводятся к скорее ошибкам кода или данных, хотя из моего опыта, большинство ошибок связано скорее с поведением, правилами, взаимодействием между объектами. Какая разница какой язык программирования, если у вас по алгоритму получилось в поле 5, а должно быть 3? Такие ошибки хорошо лечатся не «хорошим» синтаксисом, а юнит-тестами и разработкой через тестирование. Хотя для адептов функционального стиля TDD заменяется REPL-ом, но непонятно, как REPL помогает, когда смысл кода может поменяться несколько раз после написания?

Эти аргументы напоминают обещания «красивой жизни» без багов языками со сборщиками мусора. Да, непонятных багов с памятью стало меньше, но, по большому счету, они просто превратились в нулл пойнтер исключения. Да, утечек памяти стало гораздо меньше, но, по большому счету, они всё равно бывают в долгоживущих приложениях. Разумеется, что вы стали меньше думать о распределении памяти, но нельзя сказать, что не надо думать об этом вообще.

Причина 7. Я не хочу думать о каждой мелочи

Опять эмоциональный аргумент. Всё это больше зависит от разработчика, а не от языка.

Причина 8. Я люблю проверять на null

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

Причина 9. Я везде применяю шаблоны проектирования

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

Причина 10. Слишком много математики

Это тоже скорее эмоциональный аргумент. Математика есть в любом языке программирования. Другое дело, что для доказательства красоты функционального программирования чаще всего приводят примеры чистой математики или только алгоритмических задач (даже не знаю, отнесут ли все алгоритм сортировки к математике или нет). Но, кто решает алгоритмические задачи в 2010-х годах? Книге Кнута уже более 40 лет, а вы еще пишете алгоритмы сортировки? Используйте библиотеки, не изобретайте велосипед.

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

Заключение

Разумеется у функционального стиля есть светлое будущее. Скорее, удивительно, что оно не наступило еще 20 лет тому назад. А еще удивительнее это говорить спустя 60 лет после появления первого функционального языка.

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

Ведь чистое функциональное программирование многих как раз и пугает своей «красотой». Здесь полезно вспомнить историю Smalltalk, который тоже является «чистым» ООП языком, в отличие от C++, Java, C#. Но который так и не «взлетел», в отличие от языков, которые не отбросили элементы процедурного подхода. Частично, потому что не во всех задачах вам нужен «чистый» подход, а иногда он не применим вовсе. К тому же, обычно это подразумевает использование абстракций с неявными операциями позади сцены, которые обычно грозят не очень хорошей производительностью. А, если вы в своей практике встречались с задачами реализовать GUI на логическом языке (как Пролог) или Веб-разработку на Лиспе, то вы должны и сами представлять всю сложность «впихнуть невпихиваемое». Впрочем, стоит заметить, что F#, упомянутый в изначальной статье, тоже является языком многих парадигм, а не «чистым» функциональным языком.

Возможно, вы восхищаетесь другой тенденцией: множеству языков программирования базируемых на JVM или .Net платформах. Конечно, это плюс, что вы можете писать с любым синтаксическим сахаром, но получать одинаковый байт-код. Однако, всё зависит от реализации языка программирования — он может использовать многоходовые комбинации для одного вызова или основываться на рефлексии, что чревато проблемами производительности. К тому же, а кому нужно это разнообразие языков? Зачем нужны десять языков функционального программирования только с разными скобками, запятыми и двоеточиями? Нет, в самом деле.

Вы можете создать простейшую программу на новом языке за 1 день, научиться более-менее писать за 1 неделю, освоить за 1 месяц, хорошо освоить за 1 год. Ведь проблема не только в синтаксисе, но и многочисленных нюансах, «правильных» вызовов «правильных» функций, и много чего еще. Зачем, вам перескакивать с одного языка на другой? А если в каждом проекте? А если каждые пол-года? Разумеется, что это интеллектуальный вызов. Но согласны ли все работодатели оплачивать ваши внутренние потребности в интеллектуальном вызове — это вопрос. Хотя дело даже не в работодателях, но даже в вас — так как придется каждый раз одновременно решать проблемы предметной области и проблемы вхождения в новый язык программирования. А в ответ вас ожидают туманное будущее (возможно новый язык вам больше никогда не понадобится в будущем) и такое же туманное прошлое (возможно, что вы уже забудете опыт работы с предыдущими языками). Опять же возникает проблема поддержки кода — как найти человека, который поймет код, или, который мог бы научиться понимать за минимальное время.

Впрочем, если вы обратитесь к истории, то вавилонское столпотворение языков было всегда. Какие-то рождались, какие-то умирали. Кто сейчас помнит про Алгол или ПЛ/1? А ведь было еще множество других. У языков программирования своя эволюция, и выживают среди них тоже сильнейшие. А сильнейшими становятся не языки с красивым синтаксисом, а в которых есть необходимость. Такая необходимость для функциональных языков может быть связана с уменьшением времени разработки и снижением количества багов, как это описано здесь. Однако приведенные доказательства базируются на неких проектах в вакууме, так что абсолютно непонятно, что значат цифры количества строчек кода. А посему и ответ на тему статьи пока скорее «скорее нет, чем да, но будущее нас рассудит».

Автор: yuriyg_ua

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js