Re[5]: [Ann, c#7] local functions
От: Evgeny.Panasyuk Россия  
Дата: 22.05.15 18:01
Оценка:
Здравствуйте, Sinix, Вы писали:

EP>>"итераторы/await" — это всё же не замыкания. Под замыканием я понимаю прежде все захват переменных из внешнего scope.

S>Ну да, переменные(параметры) в итераторах и ко сохраняются между вызовами MoveNext()

Из своего scope, а не из чужого. yield/await в C# это во сути rewrite отдельного метода целиком в класс-автомат, но захвата из внешнего scope там нет.

EP>>Вообще, под первыми замыканиями я имел в виду:

S>А, ну так анонимные делегаты и лямбды — эт одно и то же по большому счёту. Можно их по отдельности считать, тогда больше будет

Дополнительный синтаксис загромождающий язык.

EP>>А почему для лямбд это трудно, а для local functions нет? В чём разница? Лямбды завязаны на какое-то ABI jit'а?

S>Неа, потому что лямбды — это делегаты, их значение может меняться в рантайме.

В каком смысле? Что это даёт по сравнению с локальными функциями?

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


Насколько я понял по форме отличий мало, отличаются реализации. Что мешает для старой формы сделать быструю реализацию?

S>Даже для замыканий емнип всё ок, невиртуальные вызовы могут быть заинлайнены. Надо проверять конечно, могу наврать.


Тут просто часто говорят что лямбды в C# медленные, постоянные аллокации и т.п. — по сути стоит выбор между удобством и скоростью — я вот и не понимаю почему их не оптимизировать в компиляторе, чтобы не было такой дилеммы там где её быть не должно.

EP>>Если исправят скорость лямбд, то от этого выиграет уже существующий код.

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

А создание лямбды дорогое?
Отредактировано 22.05.2015 18:03 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 22.05.2015 18:03 Evgeny.Panasyuk . Предыдущая версия .
Re[8]: [Ann, c#7] local functions
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.05.15 18:07
Оценка: 32 (1) +1
Здравствуйте, Sinix, Вы писали:

S>О! А можно подробности?


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


S>Ну а зачем в типовом скрипте что-то кроме локальных функций? Плюс, если вводить методы — клиентам надо будет прописывать сигнатуру основного метода.


Скрипт, скрипту рознь. В общем, случае скрипт может отличаться от серьезного приложения только тем, что его запускают как скрипт.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Ann, c#7] local functions
От: IT Россия linq2db.com
Дата: 22.05.15 18:23
Оценка: +1
Здравствуйте, Tesh, Вы писали:

T>Таким, что проблема, возможно, в другом и решается архитектурно.


Разве что микроархитектурно. По аналогии с микроменеджментом.
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: [Ann, c#7] local functions
От: Evgeny.Panasyuk Россия  
Дата: 22.05.15 18:24
Оценка:
Здравствуйте, IT, Вы писали:

IT>Во-вторых, функциональная парадигма органично дополняет все остальные парадигмы включая ООП. Её место внутри метода, а снаружи весьма неплохо рулят другие.


Внутри функций рулит императивный код. Отдельные элементы исторически характерные функциональным языкам типа ФВП, замыканий, АТД, PM и т.п. — действительно удобны, но они никак не определяют функциональную парадигму.
ФП это прежде всего чистота (которая кстати скорее про внешнюю сторону функций, а не внутреннюю), а не какие-нибудь замыкания (их наоборот в ФП стараются не использовать — point-free style).
Отредактировано 22.05.2015 18:28 Evgeny.Panasyuk . Предыдущая версия .
Re[4]: Копипаста и дублирование
От: Qbit86 Кипр
Дата: 22.05.15 19:19
Оценка: 52 (2)
Здравствуйте, IT, Вы писали:

IT>Копипаста и дублирование — это когда копипаста и дублирование десятков и сотен строк кода. Копипаста 5-ти строчек кода — это не копипаста.


Критерий всё-таки другой. Дублирование — это такая копипаста, которая приводит к аномалиям редактирования. Если вместо вынесения общего функционала (в том числе пятистрочного) я его копипащу, то при редактировании мне нужно поправить все места пасты, это чреватое ошибками дублирование.

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

Например, у меня функция работает с коллекцией элементов и внутри отбирает «квадратные» и «синие». Я могу либо завести локальную функцию для фильтра, либо (если не требуется замыкание) вынести в приватный метод-хелпер. Если моему коллеге нужен аналогичный фильтр, то во втором случае он его может переиспользовать; а в первом случае реализует повторно или копипастит.

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

В общем все те твои рассуждение про изолированность частей кода, про инкапсуляцию и локальность.
Глаза у меня добрые, но рубашка — смирительная!
Re[17]: Реальный пример
От: Qbit86 Кипр
Дата: 22.05.15 20:22
Оценка:
Здравствуйте, Tesh, Вы писали:

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

T>Если бы был какой-то реальный пример, то можно было бы более предметно обсуждать.

Я на работе регулярно сталкиваюсь с API, где асинхронность функций реализуется через глобальное событие. (Причём это в библиотеках стоимостью по полсотни баксов за убогую C#-обёртку над несколькими нативными и Java-библиотеками для мобильных сервисов.) По сравнению с такой моделью асинхронности, callback hell вовсе не кажется чем-то страшным и неприятным, поверьте.

Скажем, функция платежа в биллинг-системе, или постинг в социальную сеть, или что там ещё. Для функций типа StaticBunchOfFunctions.doSomething() есть публичный StaticBunchOfEvents.onSomethingEndedEvent (стиль именования сохранён, про сигнатуры EventHandler<T> никто из авторов не слышал). Ты можешь звать функцию в разных контекстах; в каком контексте ты получишь событие предсказать нельзя, как в обработчике различить источник вызова — та ещё задача. Кто угодно может звать глобальную функцию, кто угодно может подписываться, не отписываться, получать событие дважды, etc. Нужно административными методами запрещать пересекающиеся по времени вызовы, как-то протаскивать контекст, etc.

Поэтому вызов выглядит как-то так (псевдокод):
{
    ...
    local void HandleSomethingCompleted(Some weirdParams)
    {
        StaticBunchOfEvents.onSomethingEndedEvent -= HandleSomethingCompleted;
        // Perform some continuation capturing locals from outer scope.
    }
    StaticBunchOfEvents.onSomethingEndedEvent += HandleSomethingCompleted;
    StaticBunchOfFunctions.doSomething();
}


T>такой обработчик нужно выносить в отдельный метод.


Тогда обработчик в общем случае будет не методом, а полноценным классом-замыканием, с захватом полей в конструкторе и прочим синтаксическим оверхедом.
Глаза у меня добрые, но рубашка — смирительная!
Re[5]: Копипаста и дублирование
От: Evgeny.Panasyuk Россия  
Дата: 22.05.15 20:36
Оценка: +1
Здравствуйте, Qbit86, Вы писали:

Q>Критерий всё-таки другой. Дублирование — это такая копипаста, которая приводит к аномалиям редактирования. Если вместо вынесения общего функционала (в том числе пятистрочного) я его копипащу, то при редактировании мне нужно поправить все места пасты, это чреватое ошибками дублирование.


Копипаста это всегда дублирование. То что ты описываешь как "копипста без дублирования" — для этого больше подходит понятие "истина"/"truth" (как в SPOT — Single Point of Truth), то есть имеются несколько разных истин, которые временно имеют одинаковое значение.

Участки кода с разными контрактами могут иметь временно одинаковую реализацию, тем не менее это всё равно дублирование и копипаста. Вынесение такой общей реализации в отдельную функцию требует чёткого определения её контракта — тогда при изменениях реализации будет видно когда контракт меняется, а когда нет. А вот уже при изменении контракта нужно проверять всех пользователей, либо создавать отдельную функцию с новым контратком.
Необходимость формулировки и соблюдения контракта это тоже компромисс — и тут надо смотреть по ситуации что более целесообразно.
Re[18]: Реальный пример
От: Tesh США  
Дата: 22.05.15 21:11
Оценка:
Правильно я понимаю, что мы каждый метод можем представить в виде команды, которая будет что-то делать, подписываться на события, как-то их обрабатывать, а затем отписываться (по необходимости)? И в итоге у нас будут небольшие легко читаемые классы-команды?
Re[19]: Реальный пример
От: Qbit86 Кипр
Дата: 22.05.15 21:27
Оценка: +1
Здравствуйте, Tesh, Вы писали:

T>Правильно я понимаю, что мы каждый метод можем представить в виде команды, которая будет что-то делать, подписываться на события, как-то их обрабатывать, а затем отписываться (по необходимости)? И в итоге у нас будут небольшие легко читаемые классы-команды?


Небольшие классы-команды никогда не будут более легко читаемы, чем лямбды или локальные функции, если им надо захватывать замыкаемый контекст в конструкторе, или наоборот вытаскивать модифицируемые поля/свойства наружу, чтобы внешний скоуп их использовал вместо локальных переменных (как это происходит в коде, генерируемом компилятором из лямбд).
Глаза у меня добрые, но рубашка — смирительная!
Re[11]: StackOverflowException
От: WolfHound  
Дата: 23.05.15 12:40
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Ну низзя в общем случае для метода однозначно сказать: применима к нему tail call optimisation или нет.

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

И называть оптимизацией tail call elimination нельзя. Ибо если код рассчитан на TCE, а его нет, то код упадёт.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[20]: Реальный пример
От: AlexRK  
Дата: 23.05.15 12:57
Оценка:
Здравствуйте, Qbit86, Вы писали:

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


По-моему, все как раз наоборот — они всегда будут более легко читаемы, чем огромные функции с лямбдами или вложенными функциями.
Re[7]: [Ann, c#7] local functions
От: IT Россия linq2db.com
Дата: 23.05.15 15:03
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

IT>>Во-вторых, функциональная парадигма органично дополняет все остальные парадигмы включая ООП. Её место внутри метода, а снаружи весьма неплохо рулят другие.

EP>Внутри функций рулит императивный код.

Особенно хорошо императив рулит говнокодом.

EP>Отдельные элементы исторически характерные функциональным языкам типа ФВП, замыканий, АТД, PM и т.п. — действительно удобны, но они никак не определяют функциональную парадигму.


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

EP>ФП это прежде всего чистота (которая кстати скорее про внешнюю сторону функций, а не внутреннюю), а не какие-нибудь замыкания (их наоборот в ФП стараются не использовать — point-free style).


Внешняя чистота функции определяется прежде всего её внутренней реализацией, которой как раз и достигаются детерминированность и отсутствие побочных артефактов.
Если нам не помогут, то мы тоже никого не пощадим.
Re[5]: Копипаста и дублирование
От: IT Россия linq2db.com
Дата: 23.05.15 15:15
Оценка:
Здравствуйте, Qbit86, Вы писали:

[skip]

Со всем согласен.

Q>В общем все те твои рассуждение про изолированность частей кода, про инкапсуляцию и локальность.


Это всё не более чем терминологические заклинания. Изоляция и инкапсуляция — это вообще-то одно и тоже, суть — сокрытие деталей. А что ты понимаешь под локальностью я не совсем понял. Пояснишь?
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: Локальность
От: Qbit86 Кипр
Дата: 23.05.15 16:14
Оценка: +1
Здравствуйте, IT, Вы писали:

IT>А что ты понимаешь под локальностью я не совсем понял. Пояснишь?


Локальность: область видимости переменной (в том числе вложенной функции) должна быть минимальной; объявление должно быть подтянуто как можно ближе к использованию; по возможности в максимально вложенный блок (scope). Вплоть до того, что можно создать искусственный блок, намеренно ограничивающий область видимости временной переменной. В некоторых языках есть естественное органичение области видимости посредством let и where

Если в коде легко выцепить, в какой области переменная видна, и как долго «живёт», то это упрощает понимание и сопровождение кода. Снижает риски при рефакторинге.
Глаза у меня добрые, но рубашка — смирительная!
Re[7]: Локальность
От: IT Россия linq2db.com
Дата: 23.05.15 16:20
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Локальность:...


Т.е. ещё один синоним изоляции и инкапсуляции. Понятно. Спасибо.
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: [Ann, c#7] local functions
От: Evgeny.Panasyuk Россия  
Дата: 23.05.15 18:46
Оценка:
Здравствуйте, IT, Вы писали:

EP>>Отдельные элементы исторически характерные функциональным языкам типа ФВП, замыканий, АТД, PM и т.п. — действительно удобны, но они никак не определяют функциональную парадигму.

IT>Совершенно верно. Наследование, инкапсуляция и полиморфизм, особенно по отдельности, тоже никак не определяют парадигму ООП. Это просто набор удобных инструментов.

Если не использовать ни объекты, ни наследование, ни инкапсуляцию, ни полиморфизм — то это не будет является ООП.
При этом существуют языки в которых нет ни замыканий/лямбд, ни АТД, ни PM — и при этом они являются функциональными, например Unlambda.
ФВП правда есть во всех которых знаю, да. Будет ли называться язык ФЯ если убрать ФВП —

EP>>ФП это прежде всего чистота (которая кстати скорее про внешнюю сторону функций, а не внутреннюю), а не какие-нибудь замыкания (их наоборот в ФП стараются не использовать — point-free style).

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

Да, но это работает и в другую сторону: внешняя чистота функции накладывает некоторые ограничения на внутреннюю реализацию, то есть частично её определяет. При этом у чистой снаружи функции могут быть насквозь императивные внутренности. Чистый интерфейс никак не означает purely functional внутренности.
Re[9]: [Ann, c#7] local functions
От: IT Россия linq2db.com
Дата: 23.05.15 21:15
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Чистый интерфейс никак не означает purely functional внутренности.


И какой вывод? Я что-то потерял нить дискуссии.
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: [Ann, c#7] local functions
От: Evgeny.Panasyuk Россия  
Дата: 23.05.15 22:01
Оценка:
Здравствуйте, IT, Вы писали:

EP>>Чистый интерфейс никак не означает purely functional внутренности.

IT>И какой вывод? Я что-то потерял нить дискуссии.

Вообще мой поинт в следующем:
* В теле функций лучше всего себя показывает императивное программирование вкупе с некоторыми элементами характерными ФЯ — функции высшего порядка, лямбды/замыкания, и т.п. Добавление таких элементов не делает такой код функциональным — это всё то же ИП с явным мутированием и итерациями.
* Интерфейсы же лучше всего делать функциональными и как можно более чистыми.
* Функции имеют больший приоритет нежели методы объектов. Акцент нужно делать на "ООП это один из поставщиков типов для параметров функций и их реализаций", а не на "реализации методов объектов используют статические-методы-помощники" (на что в своё время сделала акцент Java).

То есть по сути — ФП снаружи, ИП с элементами ФЯ внутри, а ООП где-то сбоку.
Отредактировано 09.03.2016 14:33 Evgeny.Panasyuk . Предыдущая версия .
Re[11]: [Ann, c#7] local functions
От: fddima  
Дата: 24.05.15 03:18
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EEP>Вообще мой поинт в следующем:

EP>* В теле функций лучше всего себя показывает императивное программирование вкупе с некоторыми элементами характерными ФЯ — функции высшего порядка, лямбды/замыкания, и т.п. Добавление таких элементов не делает такой код функциональным — это всё тоже ИП с явным мутированием и итерациями.
Тут неясно тогда что такое императивный подход.
Вот в Немерле — нет стэйтментов в привычном их понимании, и они — все выражения. При этом хоть в ФЯ хоть в математике, тебе никто не мешает определить оператор ; который будет выполнять туже самую роль, что и в императивных языках. При этом, в C/C++ — есть оператор , который выполняет туже роль, что и ; — но для выражений. Дублирование на лицо. Кроме того любой стэйтмент (if/switch и т.п.) — можно представить в виде функции. А в том же Немерле — в добавок, к этому дают не уродливый синтаксис вроде IIF(x,y,z) — а то, к чему мы все привыкли.
Но, я боюсь, что я тебя не совсем правильно понял, и унесло меня не туда.

EP>* Интерфейсы же лучше всего делать функциональными и как можно более чистыми.

Интерфейс чего? Я не понял. И что значит функциональный интерфейс?

EP>* Функции имеют больший приоритет нежели методы объектов. Акцент нужно делать на "ООП это один из поставщиков типов для параметров функций и их реализаций", а не на "реализации методов объектов используют статические-методы-помощники" (на что в своё время сделала акцент Java).

EP>То есть по сути — ФП снаружи, ИП с элементами ФЯ внутри, а ООП где-то сбоку.
Если тебе кажется что все парадигмы — это лишь названия и об одном и том же, — то с философской точки зрения — это так и есть. Собственно "функция" от метода — по большому счету в практическом смысле неотличима (реализации оставляем в стороне), но когда копаем глубже — разница всё сильнее и сильнее всплывает, и начинают немного меняться подходы. Хотя в целом — всё одно.
По крайней мере — я считаю — что всё одно.

Тем не менее — я считаю, что компонентная модель — это краеугольный камень развития софта вообще. Поэтому, мне подуше nemerle-like way — ООП снаружи, а остальное должно волновать только разработчика (ну с немерле это ещё и потому, что — хочешь быть полноценнов дотнете — просто будь полноценным). К сожалению стандартной компонентной модели не существует, и весь этот ниндзя-стайл кодинг в C++ остаётся возможным только внутри модулей (я не думаю что сэры действительно захотят использовать несовместимые недохаки навроде экспорта класса — а если сэры разрабатывают библиотеки — то клиенты в любом случае будут несчастны), при этом хидеры — всё ещё нужны. Поэтому .NET и Java — жутко рулят. Потому, что этим не только можно, но ещё и удобно пользоваться.
И вот на фоне этого — ФП, ООП или ИП — для меня лично — вообще сбоку.

PS: Я повторюсь — исходный посыл я наверное не понял, и унесло меня не туда.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[21]: Реальный пример
От: fddima  
Дата: 24.05.15 03:21
Оценка:
Здравствуйте, AlexRK, Вы писали:

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

ARK>По-моему, все как раз наоборот — они всегда будут более легко читаемы, чем огромные функции с лямбдами или вложенными функциями.
Забавно, но у вас — всё наоборот. Вы хоть с кем-нибудь согласны?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.