Немерле, как я понял, больше функциональный, чем объекто-ориентированный, поэтому больший уклон в функциональщину там может смотреться вполне логичным.
C# же скорее наоборот.
Что мне не нравится в подобных попытках перенести все возможные фичи в один язык, так это то, что это не способствует единообразию кода между проектами, и получается очередной C++ с многообразием способов прострелить себе ногу.
Как разультат, легко может случиться так, что в проекте, который передадут на развитие, будет человек со своим видением использования тех же локальных функций, что приведет к огромному количеству нечитаемого тяжело поддерживаемого кода.
Здравствуйте, Tesh, Вы писали:
T>Короткие функции типа лямбд, используемых в linq не требуют именования
А если они вызываются рекурсивно или просто неоднократно? Скажем, используются при декларации отписки от события:
{
local void HandleSomeEvent(object sender, EventArgs e)
{
// Captures some variables from outer scope.
}
subject.SomeEvent += HandleSomeEvent;
_subscriptionDisposables.Add(() => { subject.SomeEvent -= HandleSomeEvent; });
...
}
T>а более крупные, объявленные внутри другого метода, только увличат объем этого метода и ухудшат читаемость.
Если выносить вложенные функции в методы того же класса, то они не смогут быть замыканиями; и не смогут гарантировать, что другие методы не начнут вызывать вынесенный, затрудняя его модификацию.
Здравствуйте, Qbit86, Вы писали:
Q>Если выносить вложенные функции в методы того же класса, то они не смогут быть замыканиями; и не смогут гарантировать, что другие методы не начнут вызывать вынесенный, затрудняя его модификацию.
Я бы вообще не использовал события из-за опасности утечки памяти (если забыли отписаться), но если и использовать, то зачем объединять код, обрабатывающий события с кодом, выполняющим подписку?
По поводу вызова обработчкика событий другими методами класса — если класс компактный и состоит из пары-тройки методов, то это не является проблемой.
Здравствуйте, Tesh, Вы писали:
T>Немерле, как я понял, больше функциональный, чем объекто-ориентированный, поэтому больший уклон в функциональщину там может смотреться вполне логичным.
Немерле как язык — это качественный гибрид, в котором ФП, ООП и МП органично дополняют друг друга.
T>C# же скорее наоборот.
C# эволюционирует в правильном направлении. Единственная проблема в том, что он уже имеет некоторые косяки, которые могут припятствовать внедрению в него новых парадигм. Это может привести к некоторой перегрузке языака, которую при проектировании с нуля можно было бы избежать.
T>Как разультат, легко может случиться так, что в проекте, который передадут на развитие, будет человек со своим видением использования тех же локальных функций, что приведет к огромному количеству нечитаемого тяжело поддерживаемого кода.
Эта проблема существует даже на программируемом калькуляторе. У каждого своё видение и способности к производству нечитабельного кода.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Tesh, Вы писали:
T>Немерле, как я понял, больше функциональный, чем объекто-ориентированный, поэтому больший уклон в функциональщину там может смотреться вполне логичным. T>C# же скорее наоборот.
Скорее наоборот. На уровне деклараций классов / методов — он будет очень похож на C# (что логично). Внутри методов — отличия есть, но в сторону бОльшего удобства. Никто всю функциональщину использовать не заставляет. С Немерле, как с языком, очень легко начать. А вот с F# (для меня лично) — лучше удавиться сразу, потому что — становится совершенно неочевидно, где же там шарп.
T>Что мне не нравится в подобных попытках перенести все возможные фичи в один язык, так это тем, что это не способствует единообразию кода между проектами и получается очередной C++ с многообразием способов прострелить себе ногу.
Всего фич на самом деле не так и много, и в том или ином виде присутствуют или реализуются в других языках. В C++ скорее мешает многословность и мешанина, даже (с моей точки зрения) в очень хорошо структурированных проектах. Кроме того, как писать код — личное дело каждого. Никакого единого стиля не было и не будет, чисто по социальным причинам, и на практике C# код только лишь похож издалека по стилю. Что по факту — вообще никак не мешает — кода или слишком много и за 5 минут его невозможно понять, или код просто хреново написан (на любом языке), или — не хватает знаний, что бы понять код.
T>Как разультат, легко может случиться так, что в проекте, который передадут на развитие, будет человек со своим видением использования тех же локальных функций, что приведет к огромному количеству нечитаемого тяжело поддерживаемого кода.
Не преувеличивайте их значимость. Это всё же простая функция. В яваскрипте таких тонны и этого вообще никого не парит. Не парят они даже тех, кто не понимает что такое замыкание.
А вот ещё у человека может быть ещё и видение всей архитектуры иное (оправданное или нет), или его просто будет раздражать не им написанный код. И как результат — вне зависимости от наличия локальных функций, его передадут ещё раз.
Здравствуйте, IT, Вы писали:
IT>А так идея не понятна? К сожалению, куска из реального проекта не имеется, потому как такие авгиевы конюшни вычищаются в первую очередь.
Так не понятно, можно ли этот класс декомпозировать или нет.
Здравствуйте, Qbit86, Вы писали:
Q>А зачем их разносить, если подписка осуществляется только в одном месте и код обработчика нежелательно вытаскивать наружу?
Почему нежелательно? Вообще зависит от того на что и где подписываетесь. Если сам объект, генерирующий события, живет только в пределах одного метода, и логика обработки события предельно проста, то можно и обычные лямбды использовать.
Если же объект живет в пределах класса, либо логика обработки события более сложная, то по-моему такой обработчик нужно выносить в отдельный метод.
Если бы был какой-то реальный пример, то можно было бы более предметно обсуждать.
Здравствуйте, Sinix, Вы писали:
VD>>Практика показала, что локальные функции помогает очистить и структурировать код. Так что мимо. S>Без обид, но нет. Скорее, получается копипаста и дублирование кода из-за того, что никто не знает, что подобный код уже написан.
Без обид, но да. Копипаста и дублирование — это когда копипаста и дублирование десятков и сотен строк кода. Копипаста 5-ти строчек кода — это не копипаста. Естественно, никто локальные фукнции в сотню строк кода писать не собирается. А вот для 5-ти строк — самое оно. Что получается при вынесении такого кода в приватный хелпер я тут уже демонстрировал.
Что касается ентерпрайзов, то лично для меня качественно реализованная бизнес логика — это прежде всего качественно изолированная бизнес логика от другой бизнес логики. Под этим следует понимать не всякие слои и прочие дробящие логику техники, а подход "вся логика в одном флаконе". Критерий качества очень простой — чем проще функциональный кусок извлекается из места дислокации без болезненных ощущений и оставшихся рудиментов, тем качество такого кода выше. Не трудно сообразить, что локальные функции при таком подходе всячески способствуют увеличению качества кода.
При работе на Немерле неоднократно наблюдалась (не только у меня одного) такая метаморфоза. Наплевав на догмы про размер метода, определённый функционал реализовывался внутри одного метода с широким использованием локальных фукнций. При достижении определённого, естественно субъективного, уровня дискомфорта, это метод вжик — и лёгким движением руки превращался в класс, где локальные функции становились приватными методами, а контекст метода распределялся по классу. В дальнейшем с одним из методов этого нового класса вполне могла произойти очередная подобная метаморфоза. Т.е. локальные функции при развитии функционала позволяют удерживать его вместе, а не дробить, что в дальнейшем способствует простоте преобразования такого функционала в более крупные компоненты.
Ну а грохнуть ненужный код без оставления рудиментов — так тут вообще много ума не надо.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, fddima, Вы писали:
T>>Что мне не нравится в подобных попытках перенести все возможные фичи в один язык, так это тем, что это не способствует единообразию кода между проектами и получается очередной C++ с многообразием способов прострелить себе ногу. F> Кроме того, как писать код — личное дело каждого.
Я бы так не сказал, есть команда и внутри команды стиль написания и оформления кода должен быть предельно единым.
F>Никакого единого стиля не было и не будет, чисто по социальным причинам, и на практике C# код только лишь похож издалека по стилю. Что по факту — вообще никак не мешает — кода или слишком много и за 5 минут его невозможно понять, или код просто хреново написан (на любом языке), или — не хватает знаний, что бы понять код.
Если говорить о разных проектах, то чем более строг язык, тем меньше вариантов реализации похожих вещей, а значит тем легче вхождение в новый проект.
Если код за 5 минут невозможно понять, то в общем случае он не должен пройти ревью и должен быть переписан.
F> Не преувеличивайте их значимость. Это всё же простая функция. В яваскрипте таких тонны и этого вообще никого не парит. Не парят они даже тех, кто не понимает что такое замыкание. F> А вот ещё у человека может быть ещё и видение всей архитектуры иное (оправданное или нет), или его просто будет раздражать не им написанный код. И как результат — вне зависимости от наличия локальных функций, его передадут ещё раз.
Сам факт возможности объявления полноценного метода внутри другого метода у меня не вызывает положительных эмоций.
Здравствуйте, IT, Вы писали:
IT>Эта проблема существует даже на программируемом калькуляторе. У каждого своё видение и способности к производству нечитабельного кода.
Вопрос в том насколько язык ограничивает, либо способствует написанию такого кода. Иначе можно возвести в абсолют: наводнить язык всевозможным количеством фич, защищая это тем, что спагетти код и без них может быть написан.
Как результат, время вхождения в проект только увеличится.
Здравствуйте, Tesh, Вы писали:
F>> Кроме того, как писать код — личное дело каждого. T>Я бы так не сказал, есть команда и внутри команды стиль написания и оформления кода должен быть предельно единым.
Тем не менее у каждой команды — свой отличимый от других стиль. Консистентность стиля внутри проекта/команды — это уже другой вопрос организации внутри команды.
F>>Никакого единого стиля не было и не будет, чисто по социальным причинам, и на практике C# код только лишь похож издалека по стилю. Что по факту — вообще никак не мешает — кода или слишком много и за 5 минут его невозможно понять, или код просто хреново написан (на любом языке), или — не хватает знаний, что бы понять код. T>Если говорить о разных проектах, то чем более строг язык, тем меньше вариантов реализации похожих вещей, а значит тем легче вхождение в новый проект. T>Если код за 5 минут невозможно понять, то в общем случае он не должен пройти ревью и должен быть переписан.
Задачи не ограничиваются только лишь написанием кода, но и багофиксинга. В период идентификации проблем, нужно "лазить" не только по коду своего проекта, но возможно и коллег, а иногда даже и по коду используемых библиотек или нижележащей платформы. Так вот во всём, с чем, вы лично не сталкивались — за 5 минут, как правило, мало что можно выяснить, и в общем случае — их код не может быть переписан (даже если вдруг и нужен фикс). А быстрота вхождения будет зависеть не сколько от языка и его фич, а сколько от знакомства с проблемой которую код решает. В этом плане, вдобавок, локальные функции будут сильно выигрывать, т.к. код и локализован и именован.
F>> Не преувеличивайте их значимость. Это всё же простая функция. В яваскрипте таких тонны и этого вообще никого не парит. Не парят они даже тех, кто не понимает что такое замыкание. F>> А вот ещё у человека может быть ещё и видение всей архитектуры иное (оправданное или нет), или его просто будет раздражать не им написанный код. И как результат — вне зависимости от наличия локальных функций, его передадут ещё раз. T>Сам факт возможности объявления полноценного метода внутри другого метода у меня не вызывает положительных эмоций.
И тем не менее — есть очень положительная практика среди других популярных языков.
Здравствуйте, Tesh, Вы писали:
IT>>А так идея не понятна? К сожалению, куска из реального проекта не имеется, потому как такие авгиевы конюшни вычищаются в первую очередь. T>Так не понятно, можно ли этот класс декомпозировать или нет.
А это тут каким боком?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Tesh, Вы писали:
T>Вопрос в том насколько язык ограничивает, либо способствует написанию такого кода. Иначе можно возвести в абсолют: наводнить язык всевозможным количеством фич, защищая это тем, что спагетти код и без них может быть написан. T>Как результат, время вхождения в проект только увеличится.
Я уже сказал, что время вхождения — зависит от опыта вообще и знакомства с предметом. Ну базовое знание языка как бы подразумевается и так.
А "спагетти" и так можно написать на любом языке. На C# и Java — например, делегаты, лямбды есть в языке. В C++ — их нет (новые C++ пока оставляем в стороне, это просто пример, а не C# vs C++). При этом в C++ делегаты разумеется используются в полный рост, тем или иным способом — в итоге код получается где-то более шумным, а между библиотеками — они разные (несовместимые). Ну и где же тут преимущество в ограничении нас в использовании фич?
Наоборот — чем больше возможностей есть — тем лучше (ещё круче, когда есть легальный способ расширения комплиятора). Тогда программисты имеют шанс воспользоваться стандартными средствами для решения своих задач.
Всё таки в контексте локальных функций — это вообще смешно звучит. Я вообще не встречал людей, у которых бы были с ними проблемы в JavaScript. А на фоне всех фич C# — эта (в плане использования / понятности) — вообще выглядит мелочью.
Здравствуйте, Tesh, Вы писали:
T>Вопрос в том насколько язык ограничивает, либо способствует написанию такого кода.
Ни у одного вменяемого языка программирования нет блокирующих функций ограничения деятельности программиста. И это правильно. Есть функции подстраховки, как, например, строгая типизация. Но даже в этом случае оставляется возможность её обхода.
T>Иначе можно возвести в абсолют: наводнить язык всевозможным количеством фич, защищая это тем, что спагетти код и без них может быть написан.
Не надо путать ковырятельство в отходах производства с освоением новых технологий. Захламить язык можно только хламом. Новые фичи, органично вписанные в язык, сделают его только мощнее. И, кстати, этих фич осталось не так уж много.
T>Как результат, время вхождения в проект только увеличится.
Это старая песня закалённого в интригах менеджера про пучок индусов вместо одного вменяемого разработчика. Тут есть только одна проблема — функция Sum для IQ не работает. Работает только функция Max. Тренеруйте своих разработчиков, гоните в шею бездарей и всё у вас получится. Посредственности могут выдавать только посредственный результат.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Qbit86, Вы писали:
Q>Быструю сортировку можно и без рекурсивных вызовов организовать, эмулировав стек, но так обычно не делают в стандартных библиотеках. То есть почему-то не спешат менять потенциальный StackOverflowEcxeption на потениальный OutOfMemoryException. Добавляют при необходимоти guard глубины рекурсии, и живут себе, поди, без штрафов к премиям.
Справедливости ради, в нормальной quicksort глубина стэка гарантированно ограничена O(ln(N)), в worst case.
Там внутри две рекурсии — по левой стороне массива и по правой. Для той у которой размер массива больше — делают ручной tail call. То есть рекурсия происходит всегда в меньшую сторону, причём это может быть как левая, так и правая сторона.
Размер меньшей части гарантированно меньше половины размера исходного массива, то есть рекурсия как минимум делится пополам, что гарантирует логарифмическую глубину.
Ограничение глубины рекурсии (причём не "реальной" глубины, а чисто алгоритмической, то есть без учёта tail call) — делается с целью перехода на алгоритм сортировки с гарантированной сложностью O(N*ln(N)) — чтобы получить общую сложность алгоритма O(N*ln(N)) в worst case.
Так, например, introsort сначала использует quicksort (потому что очень быстрая и cache-friendly), потом если глубина превышает заданный порог то делается heapsort (потому что гарантированно O(N*ln(N))), а потом ещё в некоторых вариантах когда размер всех под-масивов мал — выполняется финальное расчёсывание через insertion sort — так например во многих реализациях STL.
P.S. А вообще, на x64 проблема с переполнением стэка от рекурсии менее актуальна — достаточно зарезервировать побольше адресов под стэк.
IT>Это старая песня закалённого в интригах менеджера про пучок индусов вместо одного вменяемого разработчика. Тут есть только одна проблема — функция Sum для IQ не работает. Работает только функция Max.
Скорее, Max-Stdev. Ибо ещё и разгребать за остальными
Я кстати в плюсовом коде активно применяю лямбды в качестве локальных функций, и компилятор там, в отличие от .NET, не страдает формализмом головного мозга, а тупо инлайнит лямбды (как ИМХО и положено вести себя хорошему компилятору).