Re[4]: Интерфейсы против функций
От: mrTwister Россия  
Дата: 05.11.20 16:03
Оценка: 8 (2) +2
Здравствуйте, gyraboo, Вы писали:

G>А есть примеры исходников проектов, написанных полностью в функциональном стиле, решающие типичные задачи enterprise? Т.е. наличие некоей предметной области со сложными отношениями между сущностями, слой бизнес-операций, слой персистенции, сквозной функционал логирования, безопасности, транзакционности и т.д. Задачи типа многопоточности и распределённости не беру, т.к. тут всё понятно, ФП в этом изначально сильна.

Под рукой ссылок на конкретные исходники нет, но начать можно отсюда: How to design and code a complete program Ну и книга хороша: Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#

G>И ещё вопрос — насколько полностью ФП ПО поддерживаемо? Так же просто ли его читать, как "чистый" ООП-шный код? Просто ли его отлаживать или там всё залямбдено по самую крышу, что дебаггер не позволяет по-человечески дебажить? Есть ли сформированные стереотипы и шаблонные решения, когда ты видя большой кусок кода, понимаешь что это за шаблон и не вникаешь во все детали реализации?

На мой взгляд, если исключить неадекватов, лепящих монады и теории категорий во все дыры, то значительно проще.

1) ООП вынуждает привязывать методы к данным, хотя чаще всего в домене эта связь отсутствует. В результате, эта связь делается случайным образом, что приводит к каше в коде. Например, можно написать код в стиле ООП: "Холст.НарисуйКартину(кисть)", либо "Кисть.НарисуйКартину(холст)". Какой из этих двух вариантов правильный? Тут нет неправильного варианта. Реализован будет произвольный из них, смотря какая пятка зачесалась у программиста. Хотя в ФП стиле все однозначно: "НарисуйКартину(холст, кисть)". Нет никаких разночтений.

2) Данные жёстко связаны с методами. Какой бы из описанных в предыдущем пункте мы не выбрали вариант, мы будем жёстко связаны принятым случайным образом решением. Если мы выбираем вариант "Холст.НарисуйКартину(кисть)", то НарисуйКартину жёстко привязана к холсту и мы сможем в дальнейшем рисовать картины исключительно только на холстах. В другом варианте мы будем жёстко привязаны к кисти и сможем рисовать только кистью. С другой стороны, при ФП декомпозиции, функция НарисуйКартину(где, чем) ни к чему не привязана и может рисовать на чём угодно и чем угодно, если это пригодно для рисования.

3) ООП провоцирует на создание большого количества лишних сущностей. Для борьбы с предыдущими проблемами приходится вводить большое количество искусственных сущностей, которые отсутствуют в исходном домене. Для этих сущностей часто даже невозможно придумать адекватного названия, вот и появляются всякие FooManager, BarHelper, все это обмазывается толстым слоем абстрактных фабрик, визиторов, репозиториев и прочих паттернов, которые для эксперта из доменной области звучат, как тарабарщина и мешают тем самым применению DDD. В результате программист вместо решения задачи из предметной области воюет с визиторами и декораторами.

В результате, ФП проект со временем менее подвержен превращением в кашу. В фп стиле легче писать правильно и труднее говнокодить.
лэт ми спик фром май харт
Отредактировано 05.11.2020 16:04 mrTwister . Предыдущая версия .
Re[2]: Интерфейсы против функций
От: mrTwister Россия  
Дата: 05.11.20 14:30
Оценка: 6 (1)
Здравствуйте, gyraboo, Вы писали:

G>Я вот тоже последнее время задаюсь вопросом, что если функциональное программирование лучше (в частности, для написания распределенных и многопоточных задач), то как в нём реализовать SOLID, GRASP, ООП-паттерны и прочие достижения ООП.


Практически все ООП паттерны и прочие "достижения" нужны только для того, чтобы решать проблемы привнесенные самим ООП. Из-за отсутствующей функциональной композиции начинаются пляски с декораторами, стратегиями и прочим.
лэт ми спик фром май харт
Re[4]: Интерфейсы против функций
От: · Великобритания  
Дата: 11.11.20 09:20
Оценка: 2 (1)
Здравствуйте, yenik, Вы писали:

y> А вообще было бы прикольно, если бы C# позволял такие вещи:

java позволяет:
interface IFoo
{
    String getA();
}

IFoo a = () -> "$#@$%#%^";

Но это, ясен пень, только для интерфейсов с одним методом.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: Интерфейсы против функций
От: yenik  
Дата: 08.11.20 12:42
Оценка: 1 (1)
AA>Одна из них в том, что реализация тянет за собой сборку с интерфейсом.

Определяй интерфейс в той же сборке, и не потянет.

AA>если использовать функцию, мы не зависим ни от одной сборки.


Не факт. Если заменить myTypeInstance.DoThings() на doThings(myTypeInstance), тогда то на то и выходит.
Вызов метода экземпляра класса — это тот же вызов функции, только экземпляр передаётся в виде неявного первого параметра.
А статические методы и вовсе ничем от функций не отличаются.
Re: Интерфейсы против функций
От: vsb Казахстан  
Дата: 05.11.20 03:45
Оценка: +1
Не вижу в чём тут чистота. По сути ты сначала дал именование этому интерфейсу, а потом убрал именование. По-мне стало только хуже. Это какое-то движение в сторону JS получается, а не чистота.
Re[3]: Интерфейсы против функций
От: klopodav  
Дата: 05.11.20 08:19
Оценка: +1
vsb>>Не вижу в чём тут чистота. По сути ты сначала дал именование этому интерфейсу, а потом убрал именование. По-мне стало только хуже. Это какое-то движение в сторону JS получается, а не чистота.

AA>Имя переменной наделено смыслом и связано с типом. Только в случае интерфейса описание типа хранится отдельно от места использования.


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

И еще — пусть, например, есть несколько разных несовместимых реализаций одного интерфейса. Конкретный пример — какой-нибудь интерфейс IArchiver для действий "архивация файлов", в этом интерфейсе методы CreateArchive и AddFileToArchive, реализации — ZipArchiver и RarArchiver.
Если это же делать тупо функциями — есть риск накосячить: одну функцию в процессе использования взять соответствующую одной реализации, а другую, взаимоувязанную с ней — соответсвующую другой реализации.

В общем, это была бы равноценнная замена только для для интерфейсов, состоящих из одной функции. Для более сложных интерфейсов — нет (можно, конечно, нагородить структуры из функций, но это получились бы те же интерфейсы, только вид сбоку)
Re[3]: Интерфейсы против функций
От: gyraboo  
Дата: 05.11.20 14:51
Оценка: +1
Здравствуйте, mrTwister, Вы писали:

G>>Я вот тоже последнее время задаюсь вопросом, что если функциональное программирование лучше (в частности, для написания распределенных и многопоточных задач), то как в нём реализовать SOLID, GRASP, ООП-паттерны и прочие достижения ООП.


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


А есть примеры исходников проектов, написанных полностью в функциональном стиле, решающие типичные задачи enterprise? Т.е. наличие некоей предметной области со сложными отношениями между сущностями, слой бизнес-операций, слой персистенции, сквозной функционал логирования, безопасности, транзакционности и т.д. Задачи типа многопоточности и распределённости не беру, т.к. тут всё понятно, ФП в этом изначально сильна.
И ещё вопрос — насколько полностью ФП ПО поддерживаемо? Так же просто ли его читать, как "чистый" ООП-шный код? Просто ли его отлаживать или там всё залямбдено по самую крышу, что дебаггер не позволяет по-человечески дебажить? Есть ли сформированные стереотипы и шаблонные решения, когда ты видя большой кусок кода, понимаешь что это за шаблон и не вникаешь во все детали реализации?
Отредактировано 05.11.2020 14:59 gyraboo . Предыдущая версия . Еще …
Отредактировано 05.11.2020 14:52 gyraboo . Предыдущая версия .
Re[4]: Интерфейсы против функций
От: mrTwister Россия  
Дата: 05.11.20 15:38
Оценка: +1
Здравствуйте, klopodav, Вы писали:

K>И еще — пусть, например, есть несколько разных несовместимых реализаций одного интерфейса. Конкретный пример — какой-нибудь интерфейс IArchiver для действий "архивация файлов", в этом интерфейсе методы CreateArchive и AddFileToArchive, реализации — ZipArchiver и RarArchiver.

K>Если это же делать тупо функциями — есть риск накосячить: одну функцию в процессе использования взять соответствующую одной реализации, а другую, взаимоувязанную с ней — соответсвующую другой реализации.

Пример хороший, валидный. Без использования интерфейсов и их суррогатов в чисто-функциональном стиле, можно было бы записать так, чтобы generic функция CreateArchive (параметризованая типом архива) возвращала generic функцию AddFileToArchive, параметризованную тем же типом архива. И это было бы логично, перед тем, как добавлять файлы в архив, этот архив сначала надо создать.

Но нюанс в том, что сущностей, которые бы хорошо описывались интерфейсами со многими методами исчезающе мало. Хорошо, это значит, без нарушения interface segregation principle.
лэт ми спик фром май харт
Re[5]: Интерфейсы против функций
От: · Великобритания  
Дата: 13.11.20 11:11
Оценка: +1
Здравствуйте, mrTwister, Вы писали:

T> На мой взгляд, если исключить неадекватов, лепящих монады и теории категорий во все дыры, то значительно проще.


T> 1) ООП вынуждает привязывать методы к данным, хотя чаще всего в домене эта связь отсутствует. В результате, эта связь делается случайным образом, что приводит к каше в коде. Например, можно написать код в стиле ООП: "Холст.НарисуйКартину(кисть)", либо "Кисть.НарисуйКартину(холст)". Какой из этих двух вариантов правильный? Тут нет неправильного варианта. Реализован будет произвольный из них, смотря какая пятка зачесалась у программиста. Хотя в ФП стиле все однозначно: "НарисуйКартину(холст, кисть)". Нет никаких разночтений.

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

T> 2) Данные жёстко связаны с методами. Какой бы из описанных в предыдущем пункте мы не выбрали вариант, мы будем жёстко связаны принятым случайным образом решением.

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

T> 3) ООП провоцирует на создание большого количества лишних сущностей. Для борьбы с предыдущими проблемами приходится вводить большое количество искусственных сущностей, которые отсутствуют в исходном домене. Для этих сущностей часто даже невозможно придумать адекватного названия, вот и появляются всякие FooManager, BarHelper, все это обмазывается толстым слоем абстрактных фабрик, визиторов, репозиториев и прочих паттернов, которые для эксперта из доменной области звучат, как тарабарщина и мешают тем самым применению DDD. В результате программист вместо решения задачи из предметной области воюет с визиторами и декораторами.

Паттерны в ФП тоже есть в достатке, просто они другие.

T> В результате, ФП проект со временем менее подвержен превращением в кашу. В фп стиле легче писать правильно и труднее говнокодить.

По-моему уже давно договорились, что оптимум: ООП на глобальном уровне дизайна, ФП — локально на уровне реализации тела методов.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[7]: Интерфейсы против функций
От: ути-пути Россия  
Дата: 14.11.20 11:42
Оценка: +1
Здравствуйте, mrTwister, Вы писали:

T>Не жабные, а ООПэшные. Да, ООП можно не использовать.


Так ООП, ФП и т.п. — это сферовакуум, а в реальном мире есть вполне конкретные ЯП. И они часто поддерживают много парадигм как раз потому, что нет весомого повода загонять разработчика в какую-то одну.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[7]: Интерфейсы против функций
От: · Великобритания  
Дата: 14.11.20 15:34
Оценка: +1
Здравствуйте, mrTwister, Вы писали:

T> ·>Хрень какая-то. Выбор в данном случае будет основан на том кому нужен доступ к приватным членам и диспатчу по динамическому типу (т.е. виртуальный метод). Т.е. как раз те дыры, что пытаются заткнуть монадами и теориями категорий в ФП.

T> Приватные данные есть не сами по себе, а появляются для конкретной реализации, и появляются они в том месте, где происходит реализация. То есть не приватные данные определяют реализацию, а наоборот.
Это проблема курицы и яйца. Какая разница кто кого определяет?
Простой пример. Пусть у нас будет тип Стек. Его можно реализовать разными способами. Например, в виде списка и в виде массива. Приватными данными будут разные вещи. Например, указатель на голову и счётчик размера в первом случае; или массив и индекс в нём во втором случае.
Вот тут и диспатч, тут и приватные данные. Как это делать в ФП без монад и паттернов — неясно.

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

Или код рефакторится и пишется немного другой алгоритм... Ты как-то демонизируешь ООП.
Костылей в ФП тоже вагон и маленькая тележка.
Костыли это результат определённого процесса разработки, а не стиля программирования.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[6]: Интерфейсы против функций
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.11.20 01:53
Оценка: +1
Здравствуйте, ути-пути, Вы писали:

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

УП>Ничто не мешает на плюсах написать "НарисуйКартину(холст, кисть)", а ведь только на этом все эти претензии строятся
Не, не только на этом. На С тоже можно написать "НарисуйКартину(холст, кисть)", но это не сделает его функциональным.
Вот смотри, как это работает. Допустим, мы хотим написать функцию filter(collection, predicate) так, чтобы можно было применить её к коллекции целых, и отфильтровать все меньше определённого числа.

На классическом С нам придётся изобрести что-то типа
typedef bool (*predicate)(int, void*);
collection filter(collection c, predicate pred, void* context )

(это я пренебрегаю сложностью изобретения концепции "произвольная перечислимая коллекция" на C)
и после этого мы будем писать что-то вроде
collection filterlessthan(collection c, int limit)
{
  return filter(collection, &lessthan, &limit);
}

bool lessthan(int a, void* limit)
{
  return a < *(int*)limit;
}


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

А когда мы оборудованы возможностью делать лексические замыкания и конструировать кортежи, ООП становится не очень нужно — его можно эмулировать практически без потерь.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Интерфейсы против функций
От: mrTwister Россия  
Дата: 10.12.20 20:40
Оценка: +1
Здравствуйте, alexanderfedin, Вы писали:

A>Вероятно, потому что правильным будет "Художник.НарисуйКартину(холст, кисть)"

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

A>Мне кажется, ты не в курсе существования генерализации типов в ООП.

Перекрестись

A>То, ч то ты написал, можно резюмировать парой слов: "ООП ниасилил".

ООП ниасилил тот, кто делает классы без состояния с одним методом, потому что это не ООП
лэт ми спик фром май харт
Re[5]: Интерфейсы против функций
От: barn_czn  
Дата: 31.12.20 14:47
Оценка: :)
T>Но нюанс в том, что сущностей, которые бы хорошо описывались интерфейсами со многими методами исчезающе мало.

Ни соглашусь. Реальный мир намного сложнее, ФП ни справляется с реальным миром. Вот краткий пример.


interface ICollection
{
    TKey Add(TValue value);

    void Remove(TKey key);
}



— методы Add и Remove неразрывно связаны, как их на отдельные коллбеки разделишь? То что они идут в связке — подчеркивает семантику
Re: Интерфейсы против функций
От: barn_czn  
Дата: 31.12.20 15:18
Оценка: +1
AA>Получается, что функции высшего порядка делают код чище и проще, и интерфейсы тут как бы не особо уже нужны.
AA>Достаточно набора функций, при наличии частичного применения

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

Недавно опробовал такой класик:


class AsDisposable : IDisposable
{
    public AsDisposable(Action onDispose)
    {}

    //IDisposable
}


— тупо оберточка из делегата делающая из делегата IDisposable.
Хорошо зашло. using синтаксис придает смысл. А если б можно было имплементации фигачить лямбдами то и этого не надо было бы.
Интерфейсы против функций
От: varenikAA  
Дата: 05.11.20 02:38
Оценка:
Допустим, у нас есть сервис, который должен рассылать сообщения.
public Notificator(IEmailSender sender)

Мы внедряем зависимость через интерфейс
Теперь у нас связаны три сушности

    EmailSender
IEmailSender 
    Notificator


Отныне и навеки, так сказать.

Если же, сделать так:
type Notificator (sender: string -> string -> string -> bool) =
    if sender("guest@local", "hello", "who are you?") then


Получается, что функции высшего порядка делают код чище и проще, и интерфейсы тут как бы не особо уже нужны.
Достаточно набора функций, при наличии частичного применения и различные декораторы также становятся не нужны
ServiceUtils
    Notificator
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Интерфейсы против функций
От: SomeOne_TT  
Дата: 05.11.20 03:45
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Получается, что функции высшего порядка делают код чище и проще, и интерфейсы тут как бы не особо уже нужны.

AA>Достаточно набора функций, при наличии частичного применения и различные декораторы также становятся не нужны
AA>
AA>ServiceUtils
AA>    Notificator
AA>


Да (ты этого ответа ждал?).
Re: Интерфейсы против функций
От: scf  
Дата: 05.11.20 06:33
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Получается, что функции высшего порядка делают код чище и проще, и интерфейсы тут как бы не особо уже нужны.

AA>Достаточно набора функций, при наличии частичного применения и различные декораторы также становятся не нужны

У обоих вариантов есть плюсы и минусы. Сервис, настраиваемый функциями высшего порядка, не имеет зависимостей, не требует лишних зависимостей (если в интерфейсе n функций, а нужна только одна), его можно скопировать в другой проект и он скомпилируется и запустится без изменений кода. С другой стороны, ты заменил
IEmailSender.sender(email: String, title: String, body: String): bool
на
sender: string -> string -> string -> bool.
Я думаю, очевидно, что второй вариант без документации совершенно непонятен. Если добавить типы, как в "настоящем фп", то будет лучше, но все равно плохо:
sender: Email -> MailTitle -> MailBody -> bool

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

Вывод: ФП подход лучше обеспечивает инкапсуляцию, но она требует значительно больше усилий и строчек кода, ухудшает читабельность, усложняет доработки — проще изменить сигнатуру вызова IEmailSender.send в нотификаторе, чем "клей", преобразующий функции в коде сборки программы из независимых, изолированных функций.
Re[2]: Интерфейсы против функций
От: varenikAA  
Дата: 05.11.20 07:46
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Не вижу в чём тут чистота. По сути ты сначала дал именование этому интерфейсу, а потом убрал именование. По-мне стало только хуже. Это какое-то движение в сторону JS получается, а не чистота.


Имя переменной наделено смыслом и связано с типом. Только в случае интерфейса описание типа хранится отдельно от места использования.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Интерфейсы против функций
От: vsb Казахстан  
Дата: 05.11.20 07:57
Оценка:
Здравствуйте, varenikAA, Вы писали:

vsb>>Не вижу в чём тут чистота. По сути ты сначала дал именование этому интерфейсу, а потом убрал именование. По-мне стало только хуже. Это какое-то движение в сторону JS получается, а не чистота.


AA>Имя переменной наделено смыслом и связано с типом.


Ну вот смотри. Хочу я передать свой Sender. Во втором случае я вижу в сигнатуре только типы параметров. Мне надо читать код Notificator-а, чтобы понять, что ты передаёшь в эти параметры. Ну или читать какую-то документацию, где ты русским или английским языком будешь пытаться описать эти параметры. В первом случае у меня есть чёткий интерфейс, где ясно видно, какие названия у каких параметров этого колл-бека.

AA>Только в случае интерфейса описание типа хранится отдельно от места использования.


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

type Notificator (sender: email: string -> subject: string -> body: string -> sent successfully: bool) = ...


Хотя в этом случае получается какая-то программа в одну строчку, где слишком много информации сконцентрировано. Всё равно первый вариант лучше. А то, что он хранится отдельно от места использования — ну храни рядом с местом использования, не вижу проблемы.
Отредактировано 05.11.2020 7:58 vsb . Предыдущая версия .
Re: Интерфейсы против функций
От: gyraboo  
Дата: 05.11.20 08:44
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Получается, что функции высшего порядка делают код чище и проще, и интерфейсы тут как бы не особо уже нужны.


Я вот тоже последнее время задаюсь вопросом, что если функциональное программирование лучше (в частности, для написания распределенных и многопоточных задач), то как в нём реализовать SOLID, GRASP, ООП-паттерны и прочие достижения ООП. Или же есть какая-то замена этим подходам, если да, то какая? В плане написания полноценного бизнес-приложения, как это делается например на Java/Spring. Пока что те книги, что я читал по ФП, полной картины не дают, и в своей работе ФП я пока применяю эпизодически, внутри классических ООП-обёрток и архитектуры, построенной по принципам SOLID и Ко. Возможно, в мире ФП пока эти принципы не выкристаллизовались ещё, или я просто не знаю где искать?
Re[4]: Интерфейсы против функций
От: varenikAA  
Дата: 05.11.20 09:44
Оценка:
Здравствуйте, klopodav, Вы писали:

K>В общем, это была бы равноценнная замена только для для интерфейсов, состоящих из одной функции.


Совершенно верно, IEmailSender в Asp.Net Core именно такой интерфейс.
Проблема случается когда такой интерфейс лежит в неподходящей библиотеке. В данном случае в 3.1 aspnet.core
соотвественно о совместимости реализации можно забыть.

Для более сложных случаев в ЯП типа F# можно создать тип/алис:

type SmtpOptions = {
 host : string
 port : int    
}

type IEmailSender : options : SmtpOptions -> mail : MailMessage -> Result
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[5]: Интерфейсы против функций
От: klopodav  
Дата: 05.11.20 10:42
Оценка:
AA>Для более сложных случаев в ЯП типа F# можно создать тип/алис:
AA>

AA>type SmtpOptions = {
AA> host : string
AA> port : int    
AA>}

AA>type IEmailSender : options : SmtpOptions -> mail : MailMessage -> Result
AA>


Не, для более сложных случаев понадобилось бы еще что-то такое:

type PackOfFunctions = {
 method1 : функция(набор параметров 1...)
 method2 : функция(набор параметров 2...)    
 method3 : функция(набор параметров 3...)    
}


И это тот же интерфейс, только вид сбоку
Re: Интерфейсы против функций
От: Muxa  
Дата: 05.11.20 18:38
Оценка:
AA>Мы внедряем зависимость через интерфейс
AA>Теперь у нас связаны три сушности
EmailSender вообще никак не связан с notifier’ом.
А Notifier можно использовать и без этого конкретного EmailSender’а.
Re[2]: Интерфейсы против функций
От: varenikAA  
Дата: 06.11.20 01:25
Оценка:
Здравствуйте, Muxa, Вы писали:

M>А Notifier можно использовать и без этого конкретного EmailSender’а.


На самом деле с интерфейсами проблем много больше,
Одна из них в том, что реализация тянет за собой сборку с интерфейсом. "Хороший пример" asp.net core 3.1. интерфейс лежит в Microsoft.AspNetCore.Identity.UI.dll
Т.е. реализация будет зависит не только от dotnet core 3.1. но и еще от всего asp.net
если использовать функцию, мы не зависим ни от одной сборки.
А это уже правила хорошей разработки по Роберту Мартину.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[4]: Интерфейсы против функций
От: varenikAA  
Дата: 06.11.20 09:48
Оценка:
Здравствуйте, gyraboo, Вы писали:


G>А есть примеры исходников проектов, написанных полностью в функциональном стиле, решающие типичные задачи enterprise?


☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Интерфейсы против функций
От: yenik  
Дата: 08.11.20 12:32
Оценка:
AA>Достаточно набора функций,

А если набор функций — это 10 функций? Не легче ли инжектировать 1 интерфейс?
Re[2]: Интерфейсы против функций
От: samius Япония http://sams-tricks.blogspot.com
Дата: 08.11.20 15:20
Оценка:
Здравствуйте, yenik, Вы писали:

AA>>Достаточно набора функций,


Y>А если набор функций — это 10 функций? Не легче ли инжектировать 1 интерфейс?


Интерфейс нужно реализовать, что бы его инжектировать. А 10 функций можно взять готовых или скомбинировать их неким образом.
Более того, 10 функций можно заменить структурой с 10ю полями и в отношении количества инжектируемых функций такая структура будет ничем не хуже 1-го интерфейса. А в некотором отношении даже лучше, т.к. структуры не нужно реализовывать, достаточно лишь инициировать члены.
Re[2]: Интерфейсы против функций
От: varenikAA  
Дата: 09.11.20 05:26
Оценка:
Здравствуйте, yenik, Вы писали:

AA>>Достаточно набора функций,


Y>А если набор функций — это 10 функций? Не легче ли инжектировать 1 интерфейс?


Уверены что в одном методе нужно 10 функций?
Возможно следует использовать композицию для получения из 10-ти 1-й функции.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[4]: Интерфейсы против функций
От: varenikAA  
Дата: 09.11.20 06:22
Оценка:
Здравствуйте, yenik, Вы писали:

Y>Определяй интерфейс в той же сборке, и не потянет.

Это если есть доступ к исходному коду.

Y>Не факт. Если заменить myTypeInstance.DoThings() на doThings(myTypeInstance), тогда то на то и выходит.


не совсем, все же в этом случае зависимость односторонняя. в первом случае зависимость в обе стороны.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Интерфейсы против функций
От: yenik  
Дата: 09.11.20 10:12
Оценка:
AA>
AA>public Notificator(IEmailSender sender)
AA>


AA>>>Достаточно набора функций,


Y>>А если набор функций — это 10 функций? Не легче ли инжектировать 1 интерфейс?


AA>Уверены что в одном методе нужно 10 функций?


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

AA>Возможно следует использовать композицию для получения из 10-ти 1-й функции.


Также возможно, что эти функции нужны по отдельности.
Re[5]: Интерфейсы против функций
От: yenik  
Дата: 10.11.20 08:17
Оценка:
Y>>Определяй интерфейс в той же сборке, и не потянет.
AA>Это если есть доступ к исходному коду.

Y>>Не факт. Если заменить myTypeInstance.DoThings() на doThings(myTypeInstance), тогда то на то и выходит.


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


Не понял эту мысль. Одна сборка зависит от другой. Почему в обе стороны?
Re[3]: Интерфейсы против функций
От: yenik  
Дата: 10.11.20 08:44
Оценка:
AA>>>Достаточно набора функций,

Y>>А если набор функций — это 10 функций? Не легче ли инжектировать 1 интерфейс?


S>Интерфейс нужно реализовать, что бы его инжектировать. А 10 функций можно взять готовых или скомбинировать их неким образом.

S>Более того, 10 функций можно заменить структурой с 10ю полями и в отношении количества инжектируемых функций такая структура будет ничем не хуже 1-го интерфейса. А в некотором отношении даже лучше, т.к. структуры не нужно реализовывать, достаточно лишь инициировать члены.

Да, структура — это получше, чем 10 параметров. Но в итоге получается некое квази-ООП в стиле C с указателями на функции, в котором отсутствуют возможности ООП в стиле C++. От этого в своё время ушли, и прогрессивность такого подхода неочевидна. Хотя в каких-то случаях он может быть вполне уместен.
Необходимость реализовывать интерфейс, как всякое техническое решение, имеет плюсы и минусы. Плюс в том, что код сгруппирован, его легче поддерживать.

А вообще было бы прикольно, если бы C# позволял такие вещи:
interface IFoo
{
    string GetA();
}

var a = "%$#@$%#%^";
var bar = new<IFoo>
{
    GetA = () => { return a; }    
}
Re[4]: Интерфейсы против функций
От: samius Япония http://sams-tricks.blogspot.com
Дата: 10.11.20 09:08
Оценка:
Здравствуйте, yenik, Вы писали:

AA>>>>Достаточно набора функций,


Y>>>А если набор функций — это 10 функций? Не легче ли инжектировать 1 интерфейс?


S>>Интерфейс нужно реализовать, что бы его инжектировать. А 10 функций можно взять готовых или скомбинировать их неким образом.

S>>Более того, 10 функций можно заменить структурой с 10ю полями и в отношении количества инжектируемых функций такая структура будет ничем не хуже 1-го интерфейса. А в некотором отношении даже лучше, т.к. структуры не нужно реализовывать, достаточно лишь инициировать члены.

Y>Да, структура — это получше, чем 10 параметров. Но в итоге получается некое квази-ООП в стиле C с указателями на функции, в котором отсутствуют возможности ООП в стиле C++. От этого в своё время ушли, и прогрессивность такого подхода неочевидна. Хотя в каких-то случаях он может быть вполне уместен.


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

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

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


Y>А вообще было бы прикольно, если бы C# позволял такие вещи:

Y>
Y>interface IFoo
Y>{
Y>    string GetA();
Y>}

Y>var a = "%$#@$%#%^";
Y>var bar = new<IFoo>
Y>{
Y>    GetA = () => { return a; }    
Y>}
Y>


В F# это называется Object expression
Re[4]: Интерфейсы против функций
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 10.11.20 18:28
Оценка:
Здравствуйте, gyraboo, Вы писали:

G> Задачи типа многопоточности и распределённости не беру, т.к. тут всё понятно, ФП в этом изначально сильна.


Это миф, кстати. Многие ФЯзыки или до сих пор не умеют в многоядерность, или много лет не умели. У многих самая популярная структура данных — односвязный список, работу с которым параллелить довольно сложно. У флагмана ФП Хаскеля есть умение во многоядерность и есть разнообразие структур данных, но сборщик мусора ставит все потоки на паузу, порой надолго.
Re[4]: Интерфейсы против функций
От: varenikAA  
Дата: 11.11.20 03:28
Оценка:
Здравствуйте, yenik, Вы писали:

Y>А вообще было бы прикольно, если бы C# позволял такие вещи:

Y>
Y>var bar = new<IFoo>
Y>{
Y>    GetA = () => { return a; }    
Y>}
Y>


Внезапно, в олдскул:

        btn.setOnAction(new EventHandler<ActionEvent>() {
 
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });


И, да, это было невероятно удобно!
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[5]: Интерфейсы против функций
От: varenikAA  
Дата: 11.11.20 03:31
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Это миф, кстати. Многие ФЯзыки или до сих пор не умеют в многоядерность, или много лет не умели. У многих самая популярная структура данных — односвязный список, работу с которым параллелить довольно сложно. У флагмана ФП Хаскеля есть умение во многоядерность и есть разнообразие структур данных, но сборщик мусора ставит все потоки на паузу, порой надолго.


Разве там не регулируется кол-во потоков как в ГО (1 поток на ядро)? В этом случае, как подсказывает интуиция, не должно быть проблем со сборкой мусора. если только сборщик не наткнулся на циклические ссылки. т.е. это возможно со сборщиком что-то не так.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[6]: Интерфейсы против функций
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 11.11.20 12:53
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Разве там не регулируется кол-во потоков как в ГО (1 поток на ядро)?


В Хаскеле есть и зеленые потоки, вроде горутин, и обычные системные. Наверняка регулируется. Но толку-то, если сборщику нужно старое поколение собирать, он все равно все остановит, ибо старое поколение кучи общее для всех потоков, а чистить параллельно, как в свежих версиях Го, он пока не умеет, вроде.
Re[5]: Интерфейсы против функций
От: ути-пути Россия  
Дата: 13.11.20 07:42
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>1) ООП вынуждает привязывать методы к данным, хотя чаще всего в домене эта связь отсутствует. В результате, эта связь делается случайным образом, что приводит к каше в коде. Например, можно написать код в стиле ООП: "Холст.НарисуйКартину(кисть)", либо "Кисть.НарисуйКартину(холст)". Какой из этих двух вариантов правильный? Тут нет неправильного варианта. Реализован будет произвольный из них, смотря какая пятка зачесалась у программиста. Хотя в ФП стиле все однозначно: "НарисуйКартину(холст, кисть)". Нет никаких разночтений.


T>2) Данные жёстко связаны с методами. Какой бы из описанных в предыдущем пункте мы не выбрали вариант, мы будем жёстко связаны принятым случайным образом решением. Если мы выбираем вариант

"Холст.НарисуйКартину(кисть)", то НарисуйКартину жёстко привязана к холсту и мы сможем в дальнейшем рисовать картины исключительно только на холстах. В другом варианте мы будем жёстко привязаны к кисти и сможем рисовать только кистью. С другой стороны, при ФП декомпозиции, функция НарисуйКартину(где, чем) ни к чему не привязана и может рисовать на чём угодно и чем угодно, если это пригодно для рисования.

T>3) ООП провоцирует на создание большого количества лишних сущностей. Для борьбы с предыдущими проблемами приходится вводить большое количество искусственных сущностей, которые отсутствуют в исходном домене. Для этих сущностей часто даже невозможно придумать адекватного названия, вот и появляются всякие FooManager, BarHelper, все это обмазывается толстым слоем абстрактных фабрик, визиторов, репозиториев и прочих паттернов, которые для эксперта из доменной области звучат, как тарабарщина и мешают тем самым применению DDD. В результате программист вместо решения задачи из предметной области воюет с визиторами и декораторами.


Какие-то жабные стереотипы. Большинство языков на это не повелись, и в них все это легко и непринужденно решается свободными функциями. Да и в жабе это возможно, если рассматривать часть классов лишь как пространства имен.
Ничто не мешает на плюсах написать "НарисуйКартину(холст, кисть)", а ведь только на этом все эти претензии строятся
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[2]: Интерфейсы против функций
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.11.20 17:47
Оценка:
Здравствуйте, gyraboo, Вы писали:

G>Здравствуйте, varenikAA, Вы писали:


AA>>Получается, что функции высшего порядка делают код чище и проще, и интерфейсы тут как бы не особо уже нужны.


G>Я вот тоже последнее время задаюсь вопросом, что если функциональное программирование лучше (в частности, для написания распределенных и многопоточных задач), то как в нём реализовать SOLID, GRASP, ООП-паттерны и прочие достижения ООП. Или же есть какая-то замена этим подходам, если да, то какая? В плане написания полноценного бизнес-приложения, как это делается например на Java/Spring. Пока что те книги, что я читал по ФП, полной картины не дают, и в своей работе ФП я пока применяю эпизодически, внутри классических ООП-обёрток и архитектуры, построенной по принципам SOLID и Ко. Возможно, в мире ФП пока эти принципы не выкристаллизовались ещё, или я просто не знаю где искать?


Подвернулась презентация. Сам не смотрел, но думаю, что там тема раскрыта. На сайте Влашина я давно пасусь.
https://vimeo.com/113588389
Re[5]: Интерфейсы против функций
От: DenisCh Россия  
Дата: 14.11.20 02:08
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>1) ООП вынуждает привязывать методы к данным, хотя чаще всего в домене эта связь отсутствует. В результате, эта связь делается случайным образом, что приводит к каше в коде. Например, можно написать код в стиле ООП: "Холст.НарисуйКартину(кисть)", либо "Кисть.НарисуйКартину(холст)". Какой из этих двух вариантов правильный? Тут нет неправильного варианта. Реализован будет произвольный из них, смотря какая пятка зачесалась у программиста. Хотя в ФП стиле все однозначно: "НарисуйКартину(холст, кисть)". Нет никаких разночтений.


А если сделать Картина.Нарисовать(где, чем)?
Тогда, как и в твоём примере мы будем жёстко привзавны. Но теперь к картине. То есть мы не сможем на холсте нарисовать не картину, а, например, рисунок
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[6]: Интерфейсы против функций
От: mrTwister Россия  
Дата: 14.11.20 07:06
Оценка:
Здравствуйте, ути-пути, Вы писали:

УП>Какие-то жабные стереотипы.


Не жабные, а ООПэшные. Да, ООП можно не использовать.
лэт ми спик фром май харт
Re[6]: Интерфейсы против функций
От: mrTwister Россия  
Дата: 14.11.20 07:25
Оценка:
Здравствуйте, ·, Вы писали:


·>Хрень какая-то. Выбор в данном случае будет основан на том кому нужен доступ к приватным членам и диспатчу по динамическому типу (т.е. виртуальный метод). Т.е. как раз те дыры, что пытаются заткнуть монадами и теориями категорий в ФП.

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

По поводу диспатча — диспатч нужен не типу, а конкретному алгоритму, этот тип использующему. Но при этом задается диспатч в типе. То есть при проектировании типа нам надо иметь ввиду конкретный алгоритм. И если алгоритм немного меняется, либо надо написать немного другой алгоритм, то внезапно может выяснится, что диспатч надо делать иначе и наш старый код вместо переиспользования обрастает костылями, декораторами, адаптерами и стратегиями
лэт ми спик фром май харт
Re[6]: Интерфейсы против функций
От: mrTwister Россия  
Дата: 14.11.20 07:29
Оценка:
Здравствуйте, DenisCh, Вы писали:

DC>А если сделать Картина.Нарисовать(где, чем)?

DC>Тогда, как и в твоём примере мы будем жёстко привзавны. Но теперь к картине. То есть мы не сможем на холсте нарисовать не картину, а, например, рисунок

Только это будет не картина (картина получается в результате работы метода), а скорее функция рисования картины, которая на вход получает данные. Вот мы и пришли к функциональному программированию, когда есть функция и данные для нее, только в нагрузку получили еще кучу синтаксического оверхеда (тм) от ООП, когда вместо того, чтобы просто написать функцию мы пишем класс-функцию.
лэт ми спик фром май харт
Re[5]: Интерфейсы против функций
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.11.20 01:56
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Это миф, кстати. Многие ФЯзыки или до сих пор не умеют в многоядерность, или много лет не умели. У многих самая популярная структура данных — односвязный список, работу с которым параллелить довольно сложно.

Эмм, а в чём сложность, если он иммутабельный? Естественно, в предположении, что "работа" стоит больше, чем собственно итерирование по списку, поэтому skip(100) выполняется достаточно быстро по сравнению с process(take(100)).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Интерфейсы против функций
От: alexanderfedin США http://alexander-fedin.pixels.com/
Дата: 10.12.20 19:36
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>1) ООП вынуждает привязывать методы к данным, хотя чаще всего в домене эта связь отсутствует. В результате, эта связь делается случайным образом, что приводит к каше в коде. Например, можно написать код в стиле ООП: "Холст.НарисуйКартину(кисть)", либо "Кисть.НарисуйКартину(холст)". Какой из этих двух вариантов правильный? Тут нет неправильного варианта. Реализован будет произвольный из них, смотря какая пятка зачесалась у программиста. Хотя в ФП стиле все однозначно: "НарисуйКартину(холст, кисть)". Нет никаких разночтений.

Вероятно, потому что правильным будет "Художник.НарисуйКартину(холст, кисть)"

T>2) Данные жёстко связаны с методами. Какой бы из описанных в предыдущем пункте мы не выбрали вариант, мы будем жёстко связаны принятым случайным образом решением. Если мы выбираем вариант "Холст.НарисуйКартину(кисть)", то НарисуйКартину жёстко привязана к холсту и мы сможем в дальнейшем рисовать картины исключительно только на холстах. В другом варианте мы будем жёстко привязаны к кисти и сможем рисовать только кистью. С другой стороны, при ФП декомпозиции, функция НарисуйКартину(где, чем) ни к чему не привязана и может рисовать на чём угодно и чем угодно, если это пригодно для рисования.

Мне кажется, ты не в курсе существования генерализации типов в ООП.

T>3) ООП провоцирует на создание большого количества лишних сущностей. Для борьбы с предыдущими проблемами приходится вводить большое количество искусственных сущностей, которые отсутствуют в исходном домене. Для этих сущностей часто даже невозможно придумать адекватного названия, вот и появляются всякие FooManager, BarHelper, все это обмазывается толстым слоем абстрактных фабрик, визиторов, репозиториев и прочих паттернов, которые для эксперта из доменной области звучат, как тарабарщина и мешают тем самым применению DDD. В результате программист вместо решения задачи из предметной области воюет с визиторами и декораторами.

Смотри выше.

T>В результате, ФП проект со временем менее подвержен превращением в кашу. В фп стиле легче писать правильно и труднее говнокодить.

То, ч то ты написал, можно резюмировать парой слов: "ООП ниасилил".
Respectfully,
Alexander Fedin.
Re[7]: Интерфейсы против функций
От: alexanderfedin США http://alexander-fedin.pixels.com/
Дата: 10.12.20 19:55
Оценка:
Здравствуйте, Sinclair, Вы писали:
  Много бреда от незнания

S>На классическом С нам придётся изобрести что-то типа
S>

S>typedef bool (*predicate)(int, void*);
S>collection filter(collection c, predicate pred, void* context )
S>

S>(это я пренебрегаю сложностью изобретения концепции "произвольная перечислимая коллекция" на C)
S>и после этого мы будем писать что-то вроде
S>
S>collection filterlessthan(collection c, int limit)
S>{
S>  return filter(collection, &lessthan, &limit);
S>}

S>bool lessthan(int a, void* limit)
S>{
S>  return a < *(int*)limit;
S>}
S>


S>То есть помимо (на самом деле независимо от) возможности писать свободные функции нужна возможность описывать замыкания неявно.
S>Потому что без этого наш код сильно лучше не становится — мы сможем заманить корявую пару из (predicate, context) на функтор, но конструировать функтор придётся по-прежнему руками.

S>А когда мы оборудованы возможностью делать лексические замыкания и конструировать кортежи, ООП становится не очень нужно — его можно эмулировать практически без потерь.


template <class Collection, class Predicate>
Collection filter(const Collection &coll, const Predicate &predicate) {...}

template <class Collection, class Item>
Collection filterLessThan(const Collection &coll, const Item &limit)
{
    return filter(coll, [&limit](auto item){ return item < limit; });
}

static IEnumerable<T> Where<T>(this IEnumerable<T> coll, Func<T, bool> predicate) {...}

static IEnumerable<int> filterLessThan(this IEnumerable<int> coll, int limit)
{
    return coll.Where(item => item < limit);
}

И...?
Respectfully,
Alexander Fedin.
Re[8]: Интерфейсы против функций
От: fmiracle  
Дата: 10.12.20 20:26
Оценка:
Здравствуйте, alexanderfedin, Вы писали:

A>Много бреда от незнания


Хорошо зашел!

S>>На классическом С нам придётся изобрести что-то типа

S>...
S>То есть помимо (на самом деле независимо от) возможности писать свободные функции нужна возможность описывать замыкания неявно.


A>return filter(coll, [&limit](auto item){ return item < limit; });


Ого, какие у нас уже есть фичи в классическом С!


A>И...?

ну, это:
A>Много бреда от незнания
Re[8]: Интерфейсы против функций
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.12.20 11:25
Оценка:
Здравствуйте, alexanderfedin, Вы писали:

A>И...?

Судя по всему, вы путаете C с C++. В C нет ни class, ни template.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Интерфейсы против функций
От: bnk СССР http://unmanagedvisio.com/
Дата: 11.12.20 16:00
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>>>Достаточно набора функций,


Y>>А если набор функций — это 10 функций? Не легче ли инжектировать 1 интерфейс?


AA>Уверены что в одном методе нужно 10 функций?

AA>Возможно следует использовать композицию для получения из 10-ти 1-й функции.

Ну про это есть буква "I" в слове "SOLID".
Функций в интерфейсе должно быть столько, сколько надо, и не больше.

Если же их вообще все поодиночке передавать, то это будет IMHO капец.
Например, как будешь автокомплит (киллер-фичу ООП) реализовывать?
ООП взлетело в том числе потому, что оно позволяет "обучение по месту" в IDE (тот самый автокомплит),
давая пользователю возможность выбрать из списка вариантов, а не написать.
Re[7]: Интерфейсы против функций
От: pagid Россия  
Дата: 14.12.20 20:49
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Да, ООП можно не использовать.

От этого ФП не появится.
Re[4]: Интерфейсы против функций
От: barn_czn  
Дата: 31.12.20 14:59
Оценка:
bnk>Если же их вообще все поодиночке передавать, то это будет IMHO капец.
bnk>Например, как будешь автокомплит (киллер-фичу ООП) реализовывать?

Вместо IList передаешь структурку где Add/Remove — это тупо поля с делегатами нужной сигнатуры. Все, комплит тебе также предложит вызывать Add/Remove как только вобьешь точку.
На самом деле конечно можно обойтись или только интерфейсами, или только делегатами. Прелесть шарпа в мультипарадигменности: выбирай любой стиль, или смесь — и вперед гавнокодить )
Re[2]: Интерфейсы против функций
От: varenikAA  
Дата: 06.01.21 15:22
Оценка:
Здравствуйте, barn_czn, Вы писали:

AA>>Получается, что функции высшего порядка делают код чище и проще, и интерфейсы тут как бы не особо уже нужны.

AA>>Достаточно набора функций, при наличии частичного применения

_>Интерфейс объединяет методы общей семантикой.

_>Интерфейс только лишь из одного метода — да, вызывает вопросы. Но вот IDisposable считаю удачным.
_>Изучение кода, особенно с решарпером в обнимку, проще на интерфейсах, это мой личный опыт. Скорее всего по той же причине что интерфейс наделяет семантикой даже один метод.
_>Однозначно ответа думаю нет. Везде надо чувство меры.

_>Недавно опробовал такой класик:


_>

_>class AsDisposable : IDisposable
_>{
_>    public AsDisposable(Action onDispose)
_>    {}

_>    //IDisposable
_>}

_>


_>- тупо оберточка из делегата делающая из делегата IDisposable.

_>Хорошо зашло. using синтаксис придает смысл. А если б можно было имплементации фигачить лямбдами то и этого не надо было бы.

В плане фичей под dotnet мне больше нравится F#

// (unit -> unit) -> IDisposable
let disp f = {new IDisposable with member it.Dispose() = f() }
use it = disp (fun _ -> printfn "it is work!")
it.Dispose()

//it is work!


к сожалению, не мэйнстрим.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[7]: Интерфейсы против функций
От: Poopy Joe Бельгия  
Дата: 14.01.21 13:25
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>В Хаскеле есть и зеленые потоки, вроде горутин, и обычные системные. Наверняка регулируется. Но толку-то, если сборщику нужно старое поколение собирать, он все равно все остановит, ибо старое поколение кучи общее для всех потоков, а чистить параллельно, как в свежих версиях Го, он пока не умеет, вроде.


Разве не оно?!
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/local-gc.pdf
Re[8]: Интерфейсы против функций
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 14.01.21 14:20
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

DM>>В Хаскеле есть и зеленые потоки, вроде горутин, и обычные системные. Наверняка регулируется. Но толку-то, если сборщику нужно старое поколение собирать, он все равно все остановит, ибо старое поколение кучи общее для всех потоков, а чистить параллельно, как в свежих версиях Го, он пока не умеет, вроде.


PJ>Разве не оно?!

PJ>https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/local-gc.pdf

А оно есть в GHC из коробки? А не в чьей-то частной ветке?
Re: Интерфейсы против функций
От: barn_czn  
Дата: 14.01.21 19:33
Оценка:
IComparer<T> — вот пример уродского интерфейса который меня постоянно бесит.
Практически всегда удобнее передать делегат Comparison<T>. Но бывает что целевой класс (коллекция например с методом Sort) не умеет его принимать, подавай IComparer.
Re[9]: Интерфейсы против функций
От: Poopy Joe Бельгия  
Дата: 14.01.21 20:36
Оценка:
Здравствуйте, D. Mon, Вы писали:


DM>А оно есть в GHC из коробки? А не в чьей-то частной ветке?


Из коробки.
-qg ⟨gen⟩¶
Default
0

Since
6.12.1

Use parallel GC in generation ⟨gen⟩ and higher. Omitting ⟨gen⟩ turns off the parallel GC completely, reverting to sequential GC.

The default parallel GC settings are usually suitable for parallel programs (i.e. those using GHC.Conc.par, Strategies, or with multiple threads). However, it is sometimes beneficial to enable the parallel GC for a single-threaded sequential program too, especially if the program has a large amount of heap data and GC is a significant fraction of runtime. To use the parallel GC in a sequential program, enable the parallel runtime with a suitable -N ⟨x⟩ option, and additionally it might be beneficial to restrict parallel GC to the old generation with -qg1.
Отредактировано 14.01.2021 20:38 Poopy Joe . Предыдущая версия .
Re[10]: Интерфейсы против функций
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 14.01.21 20:47
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

DM>>А оно есть в GHC из коробки? А не в чьей-то частной ветке?


PJ>Из коробки.

PJ>Use parallel GC in generation ⟨gen⟩ and higher. Omitting ⟨gen⟩ turns off the parallel GC completely, reverting to sequential GC.

Насколько я понимаю, это совершенно другая вещь. Весь мир останавливается и старое поколение собирается в несколько тредов. Толку-то. Это не thread-local heaps и не параллельно выполнению программы.
Отредактировано 14.01.2021 20:48 D. Mon . Предыдущая версия .
Re[11]: Интерфейсы против функций
От: Poopy Joe Бельгия  
Дата: 14.01.21 22:11
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Здравствуйте, Poopy Joe, Вы писали:


DM>>>А оно есть в GHC из коробки? А не в чьей-то частной ветке?


PJ>>Из коробки.

PJ>>Use parallel GC in generation ⟨gen⟩ and higher. Omitting ⟨gen⟩ turns off the parallel GC completely, reverting to sequential GC.

DM>Насколько я понимаю, это совершенно другая вещь. Весь мир останавливается и старое поколение собирается в несколько тредов. Толку-то. Это не thread-local heaps и не параллельно выполнению программы.


Ну, я отвечал на " а чистить параллельно, как в свежих версиях Го, он пока не умеет, вроде." Чистить параллельно он умеет, он не умеет это делать конкуретно.
Кстати, уже умеет
https://www.well-typed.com/blog/aux/files/nonmoving-gc/design.pdf
с 8.10.1
Отредактировано 14.01.2021 22:18 Poopy Joe . Предыдущая версия .
Re[12]: Интерфейсы против функций
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 14.01.21 23:02
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

PJ>Ну, я отвечал на " а чистить параллельно, как в свежих версиях Го, он пока не умеет, вроде." Чистить параллельно он умеет, [s]он не умеет это делать конкуретно.


Ну это я выразился неудачно. Имел в виду именно параллельно программе, т.е. конкурентно.
Re[6]: Интерфейсы против функций
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.01.21 11:22
Оценка:
Здравствуйте, barn_czn, Вы писали:
_>- методы Add и Remove неразрывно связаны, как их на отдельные коллбеки разделишь? То что они идут в связке — подчеркивает семантику
Напишите пример кода, который работает с этой семантикой. Не выдуманный, а практически полезный. То есть я передаю вам ICollection, а вы внутри своего кода используете Add и Remove. А вот, скажем, Get или Find при этом — не используете.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Интерфейсы против функций
От: barn_czn  
Дата: 24.01.21 11:55
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, barn_czn, Вы писали:

_>>- методы Add и Remove неразрывно связаны, как их на отдельные коллбеки разделишь? То что они идут в связке — подчеркивает семантику
S>Напишите пример кода, который работает с этой семантикой. Не выдуманный, а практически полезный. То есть я передаю вам ICollection, а вы внутри своего кода используете Add и Remove. А вот, скажем, Get или Find при этом — не используете.

Легко — стек вызова. Add- добавляю аргументы, Remove — удаляю. И хочу для этого использовать именно ICollection. И попробуйте скажите что это "надуманый" пример, я тут же попрошу строгое определение надуманности.
Re[8]: Интерфейсы против функций
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.01.21 03:40
Оценка:
Здравствуйте, barn_czn, Вы писали:
_>Легко — стек вызова. Add- добавляю аргументы, Remove — удаляю. И хочу для этого использовать именно ICollection. И попробуйте скажите что это "надуманый" пример, я тут же попрошу строгое определение надуманности.
Ну почему же надуманный — совершенно нормальный пример. Но лучше бы всё же написать пример кода — потому что непонятно, что за код собирается работать с этим стеком. Вы пишете интерпретатор?
Ещё непонятно, зачем вам потребовался именно интерфейс — ведь для стека вызовов достаточно банального односвязного списка. Почему вы захотите туда передавать разные реализации интерфейса ICollection?
Непонятно, почему вы решили, что вам передадут именно стек — ведь придуманный вами ICollection может реализовывать также и очередь (FIFO), и ваш код интерпретатора просто сломается.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 25.01.2021 5:50 Sinclair . Предыдущая версия .
Re: Интерфейсы против функций
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.01.21 14:51
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Получается, что функции высшего порядка делают код чище и проще, и интерфейсы тут как бы не особо уже нужны.

AA>Достаточно набора функций, при наличии частичного применения и различные декораторы также становятся не нужны

1) Как это будет работать с DI?
2) Сигнатуры функций станут менее читаемые

Кроме этого действительно разницы между функцией и интерфейсом с одним членом-функцией нету. Если предполагается что согласованых функций будет больше одной (добавить+удалить, коллекции, итд), то лучше интерфейс.
Re[5]: Интерфейсы против функций
От: Ночной Смотрящий Россия  
Дата: 28.01.21 08:37
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>1) ООП вынуждает привязывать методы к данным, хотя чаще всего в домене эта связь отсутствует.


Ничего подобного ООП не вынуждает. Вынуждают древние книги про ООП типа Гради Буча, идеи из которых до сих пор копипастят во все мурзилки типа "Профессиональная пазработка за 21 день", пишущиеся исключительно чтобы поднять бабла на ньюбах.
При этом в упомянутом шарпе есть такая штука как extension methods, позволяющая убрать синтаксические различия между методами объектов и статическими методами. Так что руки в выборе сделать метод привязанным к стейту или нет полностью развязаны.

T>Реализован будет произвольный из них, смотря какая пятка зачесалась у программиста. Хотя в ФП стиле все однозначно: "НарисуйКартину(холст, кисть)". Нет никаких разночтений.


Ну и? Этот вариант лишает код очень приятного бонуса — discoverability. Что тут хорошего?

T>2) Данные жёстко связаны с методами.


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

T>3) ООП провоцирует на создание большого количества лишних сущностей.


Нет.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[7]: Интерфейсы против функций
От: Ночной Смотрящий Россия  
Дата: 28.01.21 08:37
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Приватные данные есть не сами по себе, а появляются для конкретной реализации, и появляются они в том месте, где происходит реализация. То есть не приватные данные определяют реализацию, а наоборот.


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

T>По поводу диспатча — диспатч нужен не типу, а конкретному алгоритму, этот тип использующему. Но при этом задается диспатч в типе.


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

T>То есть при проектировании типа нам надо иметь ввиду конкретный алгоритм.


Опять же нет. Конкретный алгоритм нужен только в случае использования виртуальных методов. А страшный и ужасный визитор как раз и предназначен для развязки алгоритмов и обрабатываемых.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.