Достаточно! JavaScript долго держал нас в своих руках своими ножными орудиями. Когда я впервые услышал термин Подъем, я понятия не имел об этом и неправильно расслышал термин хостинг. Вы с радостью объявляете переменные, используя var, и вам приходится смириться с тем, что поднимать var
(поднимать их все до самой верхней области) — это нормально. . Я не могу поверить, что JS убедила остальных в том, что все в порядке. Затем пришел ES6 и спас нас. let
исправил область видимости. const
при условии неизменности. По крайней мере, сейчас вы можете сказать, что JavaScript поддерживает функциональное программирование.
У JavaScript есть перья на шляпе —
let
иconst
.
Даже ребенок сказал бы вам, что два основных аспекта функционального программирования — это неизменность и функции первоклассных граждан, а именно. Функции высшего порядка (HOF). Другие аспекты не менее важны, но без двух верхних не может быть функционального программирования.
С самого первого дня C# поддерживал возможность обращаться с функциями как с гражданами первого класса через delegate
s. Да, концепция HOF не была лучшей в C# до появления анонимных делегатов или более поздних лямбд. Но, эй, вы могли передавать функции как данные.
Это была одна сторона медали — HOF. А как насчет другой стороны — неизменности? Как вы уже должны знать, Неизменяемость — непростая тема.
Жаль, что даже спустя 15 с лишним лет C# все еще не поддерживает неизменяемость… полностью.
C# поддерживает константы (времени компиляции) (const
) и частичную или довольно своеобразную поддержку неизменяемых переменных (readonly
). С помощью readonly
вы можете объявлять только неизменяемые переменные member. Его нельзя использовать с локальными переменными или параметрами метода. Но вот что особенного.
readonly
по-прежнему можно изменить в конструкторе.
Интересно, почему.
Продажа неизменности
Я большой поклонник неизменяемости. Уверенность, которую обеспечивает неизменяемая переменная, незаменима. Как только вы начинаете объявлять неизменяемые переменные — назначаемые только один раз, сложность вашего кода/логики распутывается и собирается поэтапно. Отдельные шаги вашей логики плавно соединяются в цепочку/конвейер, что позволяет тестировать каждый шаг независимо.
Неизменяемость для C#
Сам я не читал (никаких) предложений, но раз или два слышал слухи о добавлении поддержки неизменяемых переменных в C#. Как я уже сказал, я не просматривал предложения, поэтому я здесь мечтаю.
Есть несколько способов заставить С# поддерживать неизменяемые переменные.
Новые ключевые слова/квантификаторы
val
… как в Scala или в паре с собственным var
C#.
Несмотря на то, что он лаконичен и использует соглашение об установке, мне не нравится этот вариант по двум причинам:
var
был изобретен в первую очередь для автоматического вывода типа или того, что C# называет неявной типизацией, специально для запросов LINQ, которые возвращают анонимные типы. Несмотря на то, что команда разработчиков C# поступила разумно, сделав его более или менее универсальным, его лучше было бы назватьauto
. Поскольку C# не является чисто функциональным языком и по своей сути является императивным, так уж получилось, чтоvar
естественным образом связано с (изменяемой) переменной.var
ограничен локальными переменными. Его нельзя использовать в качестве членов класса, параметров метода и т. д.- Следует ли
var
поднять за пределы области действия функции для членов класса и других, чтобыval
стал подходящим аналогом? Другими словами,var
иval
должны свободно использоваться — локальные переменные, аргументы членов и т. д. Это не сработает, потому чтоvar
в параметрах не имеет смысла (указание на то, чтоvar
равноauto
), аval
в членах класса перекрывается сreadonly
. - Если
var
не поднят, то да, возможно,val
может сработать. А может, не совсем так. Например, если мы назначим запрос LINQ, возвращающий анонимный тип, дляval
, мы ожидаем, чтоval
выполнит автоматический вывод типа. Хотя это приятно,val
now делает больше, чем то, с чего мы начали, а именно. неизменяемые переменные. - В последние годы C# пытался понравиться сообществу Java и JavaScript больше, чем его покровителям.
val
может показаться попыткой обратиться к сообществу Scala. - Как я уже сказал,
var
иval
объединяются на словах, но не по своей цели. Там определенно есть какой-то шум.
immutable
… на языке фа-диез mutable
.
Из всех способов объявления переменных, изменяемых и неизменяемых, мне больше всего нравится F#; лучше, чем var
и val
. F# начинается с неизменяемых переменных по умолчанию и требует, чтобы вы явно указали, что хотите сделать переменную изменяемой, как в Scala. Но прелесть F# в том, что нужно украсить let
по умолчанию mutable
, чтобы он выделялся визуально.
// F# code let imCount = GetNoOfItems(); let mutable mutCount = GetNoOfItems();
Заимствуя идею, мы могли бы придумать ключевое слово immutable
.
// C# code int mutCount = GetNoOfItems(); immutable int imCount = GetNoOfItems();
Делает работу. Что нам делать с readonly
, кроме наглости? Два разных ключевых слова по сути одно и то же. Это послужит катализатором для введения еще одного для неизменяемых параметров метода. Да ладно, это не PHP 😂.
Если бы кинули на голосование, я уверен, этот вариант проиграет.
Повторное использование существующих ключевых слов/квантификаторов
const
Яростное нет. Константа отличается от неизменяемой переменной. Любая попытка повторного использования исказит смысл существующих соглашений в C#. Дело закрыто.
let
Смешанные чувства. let
был обучен запросам LINQ. Хотя (промежуточные) переменные, объявленные через let
, являются неизменяемыми[^1], это не особенно очевидно в императивном языке, таком как C#. let
в C# не предполагает того же, что и в F#.
Предположим, мы используем let
, делаем ли мы его независимым ключевым словом или модификатором существующих объявлений переменных?
// C# code let immutableCount = GetNoOfItems();
or
// C# code let int imCount = GetNoOfItems();
Я предпочитаю последнее, потому что первое находится в той же лодке, что и val
, и неявная типизация, которую мы обсуждали ранее. Последнее, кажется, соответствует всем требованиям. Только то, что let
получило это непреднамеренное ощущение хромой копии из F # и плохо применено. Мы действительно хотим эту вину?
readonly
Если все сделать правильно, то это будет идеальный выбор. Прежде чем заняться идеальной стороной этого…
- С точки зрения области действия
readonly
является противоположностьюvar
.var
застрял внутри методов, аreadonly
застрял снаружи. О, влюбленные врозь! Ранее мы обсуждали поднятиеvar
за пределы области действия функции. Здесь нам нравится помещатьreadonly
в область действия функции. var
является эквивалентом спецификатора фактического типа (или автоматически определяемого типа).readonly
— это модификатор спецификатора типа. Итак,readonly
хорошо сочетается и сvar
. Влюбленные встречаются. Итак,readonly var imCount = …
так же легитимно, как иreadonly int imCount = ...
.readonly
эквивалентенmutable
F#, производя обратный эффект.readonly
в C# делает переменную неизменной, аmutable
в F# делает наоборот. Оба являются модификаторами объявлений переменных.
Итак, объявим readonly
победителем? Да, но не совсем. Это еще не идеальный выбор. Потому что давайте напомним себе, что readonly
особенный.
Если мы внесем одно критическое изменение и больше не будем поддерживать
readonly
переменных-членов, изменяемых внутри конструктора, тогдаreadonly
будет идеальным выбором.
Я утверждаю, что мутированные readonly
переменные-члены сегодня можно переписать в однажды назначенные и действительно неизменяемые переменные. Таким образом, критическое изменение здесь действительно для победы.
По ту сторону забора
Языки, которые начинались как функциональные, такие как Scala, F# и другие, процветают; что касается неизменности. На каком-то уровне я бы сказал, что С++ тоже справился с этим; тем не менее остерегайтесь причуд.
Не будет преувеличением сказать, что за JavaScript стоит самое большое сообщество; поддержка которого благословила его let
и const
.
Давайте уделим немного времени опросу созданных нами главных конкурентов — C# и Java.
Java начиналась с поддержки неизменяемости, но не с HOF; до введения лямбда-выражений в версии 8. Итак, теперь вы можете выполнять функциональное программирование на Java; или так говорят.
С другой стороны, C# начал с (немного грубой) поддержки HOF и все еще ковыляет к поддержке неизменности. Неудивительно, что они заклятые соперники. В каком странном мире мы живем.
Излишне говорить, что должны быть и другие хорошие варианты. Люблю слышать.
C# — очень тщательно разработанный язык. Существует множество письменных материалов, подтверждающих это. В то же время он создан человеком. Таким образом, любые ограничения или недостатки, которые следует видеть, следует рассматривать с некоторой любовью.
К сожалению, каждый язык начинается с определенной разновидности — императивной, объектно-ориентированной, функциональной или любой другой, а позже обнаруживает, что с трудом или не может поддерживать другие разновидности.
Разумныйязык должен поддерживать и позволять выбирать из множества широко применяемых парадигм, методов и стилей программирования и предоставлятьразумномупрограммисту возможность реализовать решение, которое подходит проблема.
Или так сказал Бьерн Страустоуп (что-то похожее), конечно, цитируя C++. Он был прав во всех отношениях.
Этот пост изначально был опубликован на Опыте разработчика.