Существуют ли объективные, поддерживаемые аргументы в пользу разработки программного обеспечения за или против изменения значений параметров в теле функции?
Повторяющаяся ссора (в основном в хорошем шутке) в моей команде заключается в том, следует ли изменять параметры, передаваемые по значению. Пара членов команды непреклонна, что параметры никогда не должны назначаться, так что всегда можно запросить значение, первоначально переданное функции. Я не согласен и считаю, что параметры - это не более чем локальные переменные, инициализируемые синтаксисом вызова метода; если исходное значение параметра по значению важно, то может быть объявлена локальная переменная для явного хранения этого значения. Я не уверен, что кто-либо из нас очень хорошо поддерживает нашу позицию.
Это неразрешимый религиозный конфликт или есть хорошие, объективные причины для разработки программного обеспечения в любом направлении?
Примечание: принципиальный вопрос остается независимо от деталей реализации конкретного языка. Например, в JavaScript, где список аргументов всегда динамический, параметры можно рассматривать как синтаксический сахар для инициализации локальной переменной из arguments
объекта. Несмотря на это, идентификаторы, объявленные параметрами, можно рассматривать как «особые», поскольку они по-прежнему фиксируют передачу информации от вызывающего к вызываемому.
источник
Ответы:
Я принимаю третью позицию: параметры аналогичны локальным переменным: обе должны рассматриваться как неизменяемые по умолчанию. Таким образом, переменные назначаются один раз, а затем считываются, а не изменяются. В случае циклов
for each (x in ...)
переменная является неизменной в контексте каждой итерации. Причины этого:Столкнувшись с методом с кучей переменных, которые назначаются, а затем не меняются, я могу сосредоточиться на чтении кода, а не на попытке запомнить текущее значение каждой из этих переменных.
Столкнувшись с тем же методом, на этот раз с меньшим количеством переменных, но с постоянно меняющимся значением, я теперь должен помнить текущее состояние этих переменных, а также работать над тем, что делает код.
По моему опыту, первое гораздо проще для моего бедного мозга. Другие, умнее, люди, чем я, могут не иметь этой проблемы, но это помогает мне.
Что касается другого пункта:
против
Придуманные примеры, но, на мой взгляд, гораздо понятнее, что происходит во втором примере, из-за имен переменных: они передают читателю гораздо больше информации, чем та масса
r
, которая в первом примере.источник
for
циклы с неизменяемыми переменными. Инкапсуляция переменной в функции не достаточно для вас? Если у вас возникают проблемы с отслеживанием переменных в простой функции, возможно, ваши функции слишком длинные.for (const auto thing : things)
- это цикл for, и вводимая переменная является (локально) неизменной.for i, thing in enumerate(things):
также не мутирует никаких местных жителейЭто одна вещь, которая мне действительно нравится в (хорошо написанном) C ++: вы можете видеть, чего ожидать.
const string& x1
является постоянной ссылкой,string x2
является копией иconst string x3
является постоянной копией. Я знаю, что произойдет в функции.x2
будет изменено, потому что, если бы не было, не было бы причины делать его неконстантным.Поэтому, если у вас есть язык, который позволяет это, объявите, что вы собираетесь делать с параметрами. Это должно быть лучшим выбором для всех участников.
Если ваш язык не позволяет этого, я боюсь, что нет решения серебряной пули. И то и другое возможно. Единственное руководство - принцип наименьшего удивления. Используйте один подход и используйте его в своей базе кода, не смешивайте его.
источник
int f(const T x)
иint f(T x)
отличаются только в функции тела.const int x
просто чтобы прояснить, что x не изменяется внутри? Похоже, очень странный стиль для меня.const
из списка параметров, если это ему мешает. Поэтому я не думаю, что это отвечает на вопрос.Да, это «религиозный конфликт», за исключением того, что Бог не читает программы (насколько я знаю), поэтому он понижается до конфликта читабельности, который становится вопросом личного суждения. И я, конечно, сделал это, и видел, как это было сделано, в обоих направлениях. Например,
Так что здесь, просто из-за имени аргумента t0 , я бы предпочел не изменять его значение. Но предположим, что вместо этого мы просто изменили имя этого аргумента на tNow или что-то в этом роде. Тогда я бы, скорее всего, забыл о локальной копии и просто написал tNow + = dt; для этого последнего заявления.
Но наоборот, предположим, я знал, что клиент, для которого была написана программа, собирается нанять новых программистов с очень небольшим опытом, которые будут читать и работать над этим кодом. Тогда я бы, вероятно, беспокоился о том, чтобы спутать их с передачей по значению в сравнении со ссылкой, в то время как их умы на 100% заняты попыткой переварить всю бизнес-логику. Так что в этом случае я всегда объявляю локальную копию любого аргумента, который будет изменен, независимо от того, является ли он более или менее читаемым для меня.
Ответы на эти вопросы стиля возникают с опытом и редко имеют канонический религиозный ответ. Любой, кто думает, что есть один-единственный ответ (и он знает это :), вероятно, нуждается в некотором опыте.
источник