Как стать автором
Обновить

Комментарии 16

Люблю Vavr, еще с тех пор когда его звали javaslang. Пишите еще!
Хорошо, спасибо! :)
Хорошая статья!
Спасибо!
Это большой шаг для языка, но этого все еще мало
можно ли обосновать, для чего конкретно мало, и как vavr это решает?

persistent — структура должна храниться в памяти максимально долго
это весьма странное утверждение, совсем далекое от правильного определения persistent структуры («структуры, которые при модификации сохраняют все свои предыдущие состояния и ссылки на них эти состояния будут оставаться полностью работоспособными» или как-то так)
Спасибо!

можно ли обосновать, для чего конкретно мало, и как vavr это решает?

Действительно стоило пояснить. Мало для написания программ в функциональном стиле. Далее разбирается почему (например, базовые структуры для этого непригодны).

это весьма странное утверждение, совсем далекое от правильного определения persistent структуры («структуры, которые при модификации сохраняют все свои предыдущие состояния и ссылки на них эти состояния будут оставаться полностью работоспособными» или как-то так)

Здесь я попытался по-простому написать то, что вы описываете. Но я согласен, что ваше опеределение более формально и, скорее всего, подходит лучше. Поменяю. :)

Это просто взгляд с другой стороны. Если вы часто меняете состояния структуры, и старые состояния вам не всегда нужны — то это очевидно будет создавать нагрузку на GC. Так что «храниться в памяти максимально долго» — это просто формулировка того случая, когда подобные структуры эффективнее всего.
На мой взгляд библиотека очень крутая, но стоит применять ее крайне аккуратно. Она может отлично проявить себя в event-driven разработке. Однако, чрезмерное и бездумное ее использование в стандартном императивном программировании, основанном на пуле потоков, может принести много головной боли.

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


Что действительно может выстрелить в ногу так это смесь дикобраза с китом двух под подходов. Например hibernate и vavr, выкиньте первый и используйте второй для написания более функциональной обертки over JDBC без сайд эффектов и будет вам счастье.

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

Я бы не стал так идеализировать. ФП такой же подход к решению задач, как и любой другой, со своими плюсами и минусами. Из описанных свойств персистентности следует повышенная нагрузка на GC, например, при итерации по очереди будут создаваться и практически сразу удаляться временные объекты Tuple/Queue, тогда как при обычном for будет меняться лишь одна переменная-указатель (или индекс). Я не вижу, почему первый вариант будет производительнее второго и уж тем более читабельнее.


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


Ещё есть фундаментально грязные функции — работа с любым I/O, т.к. при этом меняется внешнее состояние, тут ничего не поделать. Без очень сильного колдунства не получится представить файлы, например, в виде иммутабельной структуры. Придётся хранить отдельную копию файла на каждое изменение или применять снапшоты/CoW, причём, всё это в большинстве случаев без особой практической необходимости, чисто ради поддержания идеологии.


При всём при этом, мне нравится ФП, и я его иногда применяю именно в сочетании с императивным подходом. В Java с помощью Optional и Stream можно достаточно элегантно и надёжно описывать логику, которая иначе вырождается в кучу проверок на null и обработку различных исключений. Просто не думаю, что стоит ударяться в крайности, от этого чаще всего страдает качество конечного продукта.

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

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


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


В Java с помощью Optional и Stream можно достаточно элегантно ...

Недомоноид Optional(в версии Java) и непереиспользуемый Stream. ФП в Java это все таки не самый оптимальный вариант и скорее костыль из за безысходности.

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

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

Согласен, все задачи выполнимы, на Assembler, проверенно временем. Согласен с вами что это всего лишь мое частное мнение. Но все же повторюсь, ФП гораздо ближе к мат аппарату чем ИП, следовательно выразительнее. Горькая правда в том что ЦП-ру наплевать на это так как он питается только машинным кодом.

Так я как раз к тому, что передёргивать не надо. Да, всё можно решить на ассемблере, всё так же можно решить с помощью ФП. Но эффективность (по различным критериям, замечу) обоих подходов в каждом конкретном случае может различаться на порядки. Где-то важнее производительность, где-то читабельность, где-то близость к матаппарату. И далеко не в каждой задаче этот матаппарат необходим повсеместно.


Представьте, что вы пишете игру. У вас есть граф сцены в виде дерева, у каждого элемента есть список дочерних узлов. На сцене появляется монстр, его нужно добавить в этот граф. Но так как у вас функциональный подход, дерево не мутабельно, т.е. вам нужно сделать копию с добавленным в граф новым объектом. Конечно, тут могут быть всякие оптимизации со стороны компилятора, который заметит, что вы не используете и не сохраняете нигде предыдущее состояние дерева, поэтому можно схитрить и мутировать структуру, но полагаться на это, пожалуй, наивно. Потому что если вы вдруг где-то всё же сохраните старое состояние, оптимизация сломается, и производительность просядет дичайше. Поправьте, если я что-то не так понимаю, но в таких ситуациях, упрощённо, математически некорректное x = x + 1 работает проще, быстрее и очевиднее, чем return x + 1 в некой рекурсивной функции.

Да что там далеко ходить. Буквально на днях (в ноябре) был пост, где рассказывалось, как построить стековую виртуальную машину на Хаскеле. Реально замечательный пост: habr.com/post/429530.
А потом последовал второй: habr.com/post/430956.

Из этих двух постов прекрасно видно, что использование некоторых вполне идиоматических решений (типа ленивости) зачастую приводит к жуткой неэффективности. Не ради того чтобы с чем-то поспорить, а просто если кто не видел еще — рекомендую.
Немного не соглашусь, что в Java 8 нельзя создавать бесконечные стримы: для этого есть методы Stream.generate() и Stream.iterate(). В остальном, конечно, данная библиотека существенно расширяет возможности ФП в джаве.
Жаль, автор опустил одну из моих любимых фич этой библиотеки — Either и CheckedFunction'ы — поскольку не Try'ем единым решаются проблемы с checked-exception'ами старых Java API. В остальном статья неплоха, спасибо! И ждём продолжения с лучшими практиками использования!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории