Я просто подумал, насколько проще было бы прочитать код, если бы при вызове функции вы могли написать:
doFunction(param1=something, param2=somethingElse);
Я не могу думать о каких-либо недостатках, и это сделало бы код более читабельным. Я знаю, что вы могли бы передать массив в качестве единственного аргумента и иметь ключи массива в качестве имен параметров, однако это все равно было бы не столь читабельным.
Есть ли недостаток в этом, что я скучаю? Если нет, то почему многие языки не допускают этого?
Ответы:
Указание имен параметров не всегда делает код более читабельным: например, вы бы предпочли читать
min(first=0, second=1)
илиmin(0, 1)
?Если вы принимаете аргумент предыдущего абзаца, то вполне очевидно, что указание имен параметров не должно быть обязательным. Почему не все языки делают указание имен параметров допустимым параметром?
Я могу придумать как минимум две причины:
Обратите внимание, что я не знаю ни одного языка, который реализует именованные параметры без реализации необязательных параметров (для которых требуются именованные параметры), поэтому вам следует опасаться переоценивать их преимущества читабельности, которые можно более последовательно получить с помощью определения Fluent Interfaces .
источник
Именованные параметры делают код легче для чтения, труднее писать
Когда я читаю фрагмент кода, именованные параметры могут вводить контекст, облегчающий понимание кода. Рассмотрим, например , этот конструктор:
Color(1, 102, 205, 170)
. Что на земле это значит? Действительно,Color(alpha: 1, red: 102, green: 205, blue: 170)
было бы намного легче читать. Но, увы, компилятор говорит «нет» - он хочетColor(a: 1, r: 102, g: 205, b: 170)
. При написании кода с использованием именованных параметров вы тратите ненужное количество времени на поиск точных имен - проще забыть точные имена некоторых параметров, чем забыть их порядок.Это однажды меня поразило, когда я использовал
DateTime
API, у которого было два родственных класса для точек и длительностей с почти идентичными интерфейсами. ПокаDateTime->new(...)
принимаютсяsecond => 30
аргументы,DateTime::Duration->new(...)
разыскиваютсяseconds => 30
и аналогичные для других подразделений. Да, это имеет смысл, но это показало мне, что именованные параметры ≠ простота использования.Плохие имена даже не облегчают чтение
Другим примером того, как именованные параметры могут быть плохими, является, вероятно, язык R. Этот фрагмент кода создает график данных:
Вы видите два позиционных аргумента для строк данных x и y , а затем список именованных параметров. Есть еще много опций с настройками по умолчанию, и в списке указаны только те, настройки по умолчанию которых я хотел изменить или явно указать. Как только мы проигнорируем, что этот код использует магические числа, и может извлечь выгоду из использования перечислений (если R имел их!), Проблема в том, что многие из этих имен параметров довольно неразборчивы.
pch
на самом деле символ графика, символ, который будет отображаться для каждой точки данных.17
это пустой круг или что-то в этом роде.lty
тип линии Здесь1
сплошная линия.bty
это тип коробки. Установка этого"n"
позволяет избежать рисования рамки вокруг графика.ann
контролирует появление аннотаций оси.Для тех, кто не знает, что означает каждая аббревиатура, эти варианты довольно запутанные. Это также показывает, почему R использует эти метки: не как самодокументируемый код, а (будучи языком с динамической типизацией) в качестве ключей для сопоставления значений с их правильными переменными.
Свойства параметров и подписей
Сигнатуры функций могут иметь следующие свойства:
Различные языки приземляются в разных координатах этой системы. В C аргументы упорядочены, безымянны, всегда обязательны и могут быть переменными. В Java ситуация аналогична, за исключением того, что подписи могут быть перегружены. В Задаче C подписи упорядочены, названы, обязательны и не могут быть перегружены, потому что это всего лишь синтаксический сахар вокруг C.
Динамически типизированные языки с varargs (интерфейсы командной строки, Perl, ...) могут эмулировать необязательные именованные параметры. Языки с перегрузкой размера сигнатуры имеют нечто вроде позиционных необязательных параметров.
Как не реализовать именованные параметры
Когда мы думаем об именованных параметрах, мы обычно предполагаем именованные, необязательные, неупорядоченные параметры. Реализовать это сложно.
Необязательные параметры могут иметь значения по умолчанию. Они должны быть определены вызываемой функцией и не должны компилироваться в вызывающий код. В противном случае значения по умолчанию не могут быть обновлены без перекомпиляции всего зависимого кода.
Теперь важный вопрос - как аргументы фактически передаются в функцию. При упорядоченных параметрах аргументы могут передаваться в регистре или в их внутреннем порядке в стеке. Когда мы на мгновение исключаем регистры, проблема заключается в том, как поместить неупорядоченные необязательные аргументы в стек.
Для этого нам нужен некоторый порядок над необязательными аргументами. Что делать, если код декларации изменен? Поскольку порядок не имеет значения, переупорядочение в объявлении функции не должно изменять положение значений в стеке. Мы также должны рассмотреть возможность добавления нового необязательного параметра. С точки зрения пользователей это выглядит так, потому что код, который ранее не использовал этот параметр, должен работать с новым параметром. Таким образом, это исключает порядок, такой как использование порядка в объявлении или алфавитный порядок.
Рассмотрим это также в свете подтипирования и принципа подстановки Лискова - в скомпилированном выводе те же инструкции должны иметь возможность вызывать метод для подтипа с возможно новыми именованными параметрами и для супертипа.
Возможные реализации
Если у нас не может быть определенного порядка, нам нужна неупорядоченная структура данных.
Самая простая реализация - просто передать имя параметров вместе со значениями. Вот как именованные параметры эмулируются в Perl или с помощью инструментов командной строки. Это решает все проблемы расширения, упомянутые выше, но может быть огромной тратой пространства - не вариант для кода, критичного к производительности. Кроме того, обработка этих именованных параметров теперь намного сложнее, чем просто извлечение значений из стека.
На самом деле, требования к пространству могут быть уменьшены с помощью объединения строк, что может уменьшить последующее сравнение строк до сравнения указателей (за исключением случаев, когда невозможно гарантировать, что статические строки фактически объединены, и в этом случае две строки должны будут сравниваться в подробно).
Вместо этого мы могли бы также передать умную структуру данных, которая работает как словарь именованных аргументов. Это дешево для вызывающей стороны, потому что набор ключей статически известен в месте вызова. Это позволило бы создать идеальную хеш-функцию или рассчитать три. Вызываемый все равно должен будет проверить наличие всех возможных имен параметров, что несколько дорого. Нечто подобное используется в Python.
Так что это просто слишком дорого в большинстве случаев
Если функция с именованными параметрами должна быть должным образом расширяемой, окончательное упорядочение не может быть принято. Так что есть только два решения:
Другие подводные камни
Имена переменных в объявлении функции обычно имеют некоторое внутреннее значение и не являются частью интерфейса - даже если многие инструменты документации по-прежнему будут их отображать. Во многих случаях вам понадобятся разные имена для внутренней переменной и соответствующего именованного аргумента. Языки, которые не позволяют выбирать внешне видимые имена именованного параметра, не получают много из них, если имя переменной не используется с учетом вызывающего контекста.
Проблема с эмуляцией именованных аргументов заключается в отсутствии статической проверки на стороне вызывающей стороны. Это особенно легко забыть при передаче словаря аргументов (глядя на вас, Python). Это важно , потому что прохождение словаря является общим обходным путем, например , в JavaScript:
foo({bar: "baz", qux: 42})
. Здесь ни типы значений, ни наличие или отсутствие определенных имен не могут быть проверены статически.Эмуляция именованных параметров (в статически типизированных языках)
Простое использование строк в качестве ключей и любого объекта в качестве значения не очень полезно при наличии средства проверки статического типа. Однако именованные аргументы можно эмулировать структурами или объектными литералами:
источник
it is easier to forget the exact names of some parameters than it is to forget their order
... это интересное утверждение.По той же причине, что венгерская нотация больше не используется широко; Intellisense (или его моральный эквивалент в IDE не Microsoft). Большинство современных IDE расскажут вам все, что вам нужно знать о параметре, просто наведя указатель на параметр.
Тем не менее, многие языки поддерживают именованные параметры, включая C # и Delphi. В C # это необязательно, поэтому вам не нужно его использовать, если вы этого не хотите, и есть другие способы специально объявить члены, такие как инициализация объекта.
Именованные параметры в основном полезны, когда вы хотите указать только подмножество необязательных параметров, а не все из них. В C # это очень полезно, потому что вам больше не нужна куча перегруженных методов, чтобы предоставить программисту такую гибкость.
источник
sin(radians=2)
, вам не нужно "Intellisense".Bash, безусловно, поддерживает этот стиль программирования, и Perl и Ruby поддерживают передачу списков имен / значений параметров (как и любой язык с поддержкой хэшей / карт). Ничто не мешает вам выбрать определение структуры / записи или хэша / карты, которая присоединяет имена к параметрам.
Для языков, которые изначально хранят хеш / карту / ключевое значение, вы можете получить желаемую функциональность, просто приняв идиому для передачи хешей ключ / значение в ваши функции / методы. После того, как вы опробовали его в проекте, вы лучше поймете, получили ли вы что-либо: от повышения производительности за счет простоты использования или улучшения качества за счет уменьшения дефектов.
Обратите внимание, что опытные программисты привыкли передавать параметры по порядку / слоту. Вы также можете обнаружить, что эта идиома полезна только тогда, когда у вас есть несколько аргументов (скажем,> 5/6). А поскольку большое количество аргументов часто указывают на (чрезмерно) сложные методы, вы можете обнаружить, что эта идиома полезна только для самых сложных методов.
источник
Я думаю, что это та же самая причина, почему C # более популярен, чем VB.net. Хотя VB.NET более «читабелен», например, вместо закрывающей скобки вы набираете «end if», но в итоге получается больше материала, который дополняет код и в конечном итоге усложняет его понимание.
Оказывается, что сделать код проще для понимания, это краткость. Чем меньше, тем лучше. Имена параметров функций в любом случае, как правило, довольно очевидны, и в действительности не помогают вам понять код.
источник
Именованные параметры являются решением проблемы рефакторинга исходного кода и не предназначены для того, чтобы сделать исходный код более читабельным . Именованные параметры используются для помощи компилятору / анализатору в разрешении значений по умолчанию для вызовов функций. Если вы хотите сделать код более читабельным, чем добавлять содержательные комментарии.
Языки, которые трудно реорганизовать, часто поддерживают именованные параметры, потому
foo(1)
что они ломаются при изменении сигнатурыfoo()
, но сfoo(name:1)
меньшей вероятностью ломаются, требуя меньше усилий от программиста для внесения измененийfoo
.Что вы делаете, когда вам нужно ввести новый параметр в следующую функцию, и есть сотни или тысячи строк кода, вызывающих эту функцию?
Большинство программистов будут делать следующее.
Теперь рефакторинг не требуется, и функция может выполняться в устаревшем режиме, когда
gender
равно нулю.Для конкретного
gender
значения теперь HARDCODED в вызовеage
. Как этот пример:Программист посмотрел определение функции, увидел, что она
age
имеет значение по умолчанию0
и использовал это значение.Теперь значение по умолчанию для
age
в определении функции совершенно бесполезно.Именованные параметры позволяют избежать этой проблемы.
Новые параметры могут быть добавлены,
foo
и вам не нужно беспокоиться о порядке их добавления, и вы можете изменять значения по умолчанию, зная, что установленное вами значение действительно является истинным значением по умолчанию.источник