Именованные аргументы (параметры) для удобства чтения

11

Давным-давно я много программировал в ADA, и было нормально называть аргументы при вызове функции - SomeObject.DoSomething (SomeParameterName => someValue);

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

Вы можете утверждать, что всегда должно быть очевидно, что означает аргумент, но если у вас есть логический аргумент, и вызывающие абоненты передают «true» или «false», то квалификация значения с именем делает сайт вызова более читабельным.

contentFetcher.DownloadNote (примечание, руководство: правда);

Думаю, я мог бы создать Enums вместо использования true или false (в данном случае Manual, Automatic).

Что вы думаете о том, чтобы иногда использовать именованные аргументы для облегчения чтения кода?

Damian
источник
Параметр комментария поверх методов также помогает.
Амир Резаи
1
@ amir-rezaei: комментарии к параметрам в верхней части методов помогают, только если вы можете доверять комментариям. Если у вас нет хороших разработчиков и хороших процессов проверки кода, я бы не стал доверять комментариям.
Btilly
Как единовременный пользователь Ada, я иногда пользуюсь, как вы описываете. Вот как я помню, что они использовались в Ada, кстати, - я бы не назвал это «ненормальным», но слово «нормальный», по-видимому, подразумевает, что в большинстве вызовов указываются имена параметров, что не так, как я помню. Конечно, соглашения могут быть разными, но ненужный беспорядок - плохое соглашение на любом языке IMO.
Steve314
Я согласен с тем, что вы используете в Аде - это было не то, что мы делали все время, но где это помогло.
Дамиан

Ответы:

7

Это было предложено при разработке C ++, и Страуструп обсуждает это в своей статье «Проектирование и развитие C ++», стр. 153 и далее. Предложение было правильно сформулировано и основано на предыдущем опыте работы с Ada. Это не было принято.

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

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

Это также может быть обработано с помощью объектов, а не вызовов функций. Вместо вызова GetWindow с дюжиной параметров создайте класс Window с дюжиной личных переменных и при необходимости добавьте установщики. Сцепляя сеттеры, можно написать что-то вроде my_window.SetColor(green).SetBorder(true).SetBorderSize(3);. Также возможно иметь разные функции с разными значениями по умолчанию, которые вызывают функцию, которая фактически выполняет эту работу.

Если вы просто беспокоитесь о влиянии документации contentFetcher.DownloadNote(note, manual : true);, вы всегда можете написать что-то вроде этого contentFetcher.DownloadNote(note, /* manual */ true);, так что это не очень полезно в документации.

Дэвид Торнли
источник
Как ни странно, когда я перешел из Ada в C, я начал использовать соглашение, которое вы описали - хотя рецензенты его ненавидели. Согласитесь, не используйте его для большого количества параметров.
Дамиан
7

Я думаю, что проблема заключается в том, чтобы сделать плохой код более читабельным, а не в «лучшей практике».

Наличие метода (или подрядчика), который принимает 20 параметров, является «неприятным запахом» и может быть связано с проблемой в вашем дизайне. Однако если я вынужден работать над кодом, когда методы принимают много параметров, то именованный параметр делает код менее трудным для понимания.

Если у методов есть только 1 или 2 параметра, и из имени метода ясно, что это за параметр, то именованный параметр ничего не добавляет. Это идеальный случай.

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

Ян
источник
1
Функция с двумя параметрами может сбивать с толку, если оба параметра имеют одинаковый тип и не имеют понятия, какой именно. Конечно, вы можете называть функцию так, чтобы она представляла эту подсказку, но вы все равно просто делаете то, что делают имена параметров, за исключением того, что вы обязываете включать это многословие, даже когда контекст (например, выражения, которые предоставляют параметры) сделать очевидным, какой параметр какой.
Steve314
1
@ Steve314 Пример:void TrackDataChange(Data oldData, Data newData)
Александр
3

Я согласен, что добавление имени параметра делает его более читабельным. Тем не менее, большинство книг, которые я прочитал, похоже, считают булевы переключатели плохой практикой. Я иногда делаю это:

public Content DownloadNote(Note note)
{
    return downloadNote(note, manual: false);
}

public Content DownloadNoteManually(Note note)
{
    return downloadNote(note, manual: true);
}

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

Скотт Уитлок
источник
3
Если у вас есть x вариантов, вы сделаете 2 ^ x фронтэндов?
apoorv020
@ apoorv020 - если бы у меня было достаточно параметров для вызова метода, чтобы значение 2 ^ x стало значительным, я создал бы новый класс для хранения значений параметров и просто передал бы один параметр.
Скотт Уитлок
@ scott-whitlock: вариант 1 - создать объект, задать свойства x, вызвать метод один раз с вашим объектом. Вариант 2 - вызвать метод с x именованными параметрами. Что лучше, зависит от вашего языка. В динамически типизированном языке, для варианта 1 требуется значительно больше стандартного набора без усиления, и поэтому он хуже. В статически типизированном языке вы все еще добавляете шаблон, но тесты для ключей с неправильным именем должны выполняться во время компиляции, а не во время выполнения. Поэтому вариант 1 лучше в C #, но вариант 2 - явный выигрыш в Python.
btilly
@btilly - как указал Ян, Чистый код четко говорит вам не иметь функций с более чем 2 или 3 параметрами. Честно говоря, речь шла о Java, которая статически типизирована. ОП также спрашивает о C #, который типизирован статически. Я все же предпочел бы использовать перегрузки функций и / или другие имена с точно именованными функциями, чем длинный список параметров.
Скотт Уитлок
@ Скотт-Уитлок: мы на самом деле не согласны? Мы согласны с тем, что лучше в C #. Мы оба знаем, что говорит Чистый Кодекс. Моя точка зрения заключалась в том, что важно понять, почему это хорошо, чтобы вы знали, когда совет подходит или не подходит для другой среды.
Btilly
3

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

При этом именованные параметры не должны быть альтернативой созданию разумных списков аргументов, использованию вспомогательных объектов (для «связывания» семантически связанных аргументов) и использования перечислений, где это уместно.

Uri
источник
0

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

Я думаю, что это более читабельно, в некоторой степени; но, как уже упоминали другие, наличие большого количества параметров является запахом кода, поэтому я не вижу большой пользы для этого в объектно-ориентированном языке, таком как C #.

TMN
источник