Подтвердить что ты не робот

Какой код более читабельен?

Предположим, что у меня есть два метода bool Foo() и bool Bar(). Что из следующего более читаемо?

if(Foo())
{
    SomeProperty = Bar();
}
else
{
    SomeProperty = false;
}

или

SomeProperty = Foo() && Bar();

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

Как вы думаете? Существуют ли другие факторы, влияющие на решение? Например, если выражение && длиннее одной строки, которая может поместиться на экране, должен ли я использовать первый?


Пояснения:

Несколько вещей, которые я должен был включить в первоначальный вопрос, который вызвал ответы.

  • Bar() может быть дороже, чем Foo(), но ни один из методов не должен иметь побочных эффектов.
  • Эти методы называются более подходящими, а не как в этом примере. Foo() сводится к чему-то вроде CurrentUserAllowedToDoX() и Bar() больше похоже, XCanBeDone()
4b9b3361

Ответ 1

Я согласен с общим мнением, что Foo() && Bar() является разумным , если только это не так, что Bar() полезен для его побочных эффектов, а также для его значения.

Если это так, что Bar() полезен для его побочных эффектов, а также для его значения, моим первым выбором было бы перепроектировать Bar(), так что производство его побочных эффектов и вычисление его значения были отдельными методами.

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

Например, при выборе между

if (NetworkAvailable())
  success = LogUserOn();
else
  success = false;

и

success = NetworkAvailable() && LogUserOn();

Я бы взял бывшую; для меня слишком легко упустить важный побочный эффект в последнем.

Однако, если бы это был выбор между

if (NetworkAvailable())
  tryWritingToNetworkStorage = UserHasAvailableDiskQuota();
else
  tryWritingToNetworkStorage = false;

и

tryWritingToNetworkStorage = NetworkAvailable() && UserHasAvailableDiskQuota();

Я бы выбрал последний.

Ответ 2

Мне нравится это сокращенное обозначение, предполагающее, что ваш язык позволяет:

SomeProperty = Foo() ? Bar() : false;

Ответ 3

SomeProperty = Foo() && Bar();

Это более читаемо. Я не понимаю, как кто-то может выбрать другого, честно говоря. Если && выражение длиннее 1 строки, разделите его на две строки...

SomeProperty = 
   Foo() && Bar();

      -or-

SomeProperty = Foo() && 
               Bar();

Это едва ухудшает читаемость и понимание IMHO.

Ответ 4

Это зависит от того, что делают Foo и Bar.

Например, IsUserLoggedIn() && IsUserAdmin() определенно будет лучше, чем &&, но есть и другие комбинации (я не могу придумать ничего), где ifs будет лучше.

В целом я бы рекомендовал &&.

Ответ 5

Ни. Я бы начал с переименования SomeProperty, Foo и Bar.

Я имею в виду, что вы должны структурировать свой код, чтобы четко выразить свои намерения. С различными функциями я могу использовать разные формы. Однако, как бы то ни было, любая форма в порядке. Рассмотрим:

IsFather = IsParent() && IsMale();

и

if (FPUAvailable()) {
    SomeProperty = LengthyFPUOperation();
} else {
    SomeProperty = false;
}

Здесь первая форма подчеркивает логическую и взаимосвязь. Второй - это короткое замыкание. Я бы никогда не написал первый пример во второй форме. Вероятно, я предпочел бы вторую форму для второго примера, особенно если бы я стремился к ясности.

Точка, трудно ответить на этот вопрос с помощью SomeProperty и Foo() и Bar(). Есть некоторые хорошие, общие ответы, защищающие && для обычных случаев, но я бы никогда полностью не исключал вторую форму.

Ответ 6

Как вы думаете, каким образом люди могут неправильно интерпретировать второй? Как вы думаете, они забудут, что && shortcircuits и беспокоиться о том, что произойдет, если второе условие вызывается, когда первое ложно? Если это так, я бы не стал беспокоиться об этом - они были бы одинаково путаны:

if (x != null && x.StartsWith("foo"))

который я не думаю, что многие люди переписывали бы в качестве первой формы.

В принципе, я бы пошел со вторым. При подходящем описательном имени переменной (и условиях) это должно быть абсолютно нормально.

Ответ 7

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

Ответ 8

Я бы пошел на второй, но, вероятно, напишу его как в первый раз, а потом я его изменил:)

Ответ 9

Когда я прочитал первый, это было не сразу очевидным. SomeProperty был логическим свойством, и Bar() не возвращал логическое значение, пока не прочитал еще часть инструкции.

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

В связи с тем, что утверждение требует, чтобы я ссылался на другую часть инструкции, чтобы интерполировать, что SomeProperty и Bar() являются логическими по своей природе, я бы использовал второй.

Во втором случае сразу в одной строке кода сразу видно все следующие факты:

  • SomeProperty имеет значение boolean.
  • Foo() и Bar() возвращают значения, которые могут быть интерпретированы как логические.
  • SomeProperty должен быть установлен в false, если оба Foo() и Bar() не интерпретируются как истинные.

Ответ 10

Первый, гораздо более отлаживаемый

Ответ 11

Я думаю, что лучший способ - использовать SomeProperty = Foo() && Bar(), потому что он намного короче. Я думаю, что любой нормальный .NET-программист должен знать, как работает && -operator.

Ответ 12

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

Ответ 13

Подождите минуту. Эти утверждения даже не эквивалентны, не так ли? Я смотрел на них несколько раз, и они не оценивают одно и то же.

Сокращение для первой версии будет использовать тернарный оператор, а не оператор "и".

SomeProperty = foo() ? bar: false

Однако логическая ошибка в стороне, я согласен со всеми, что более короткая версия более читаема.

Изменить - добавлено

Опять же, если я ошибаюсь и нет логической ошибки, тогда второй способ более читабельен, потому что он очень очевиден, что делает код.

Изменить снова - добавлено больше:

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

Ответ 14

Если, как вы указываете, Bar() имеет побочные эффекты, я бы предпочел более явный способ. В противном случае некоторые люди могут не понимать, что вы намереваетесь использовать короткие замыкания.

Если Bar() самосохраняется, я бы пошел на более сжатый способ выражения кода.

Ответ 15

Если первая версия выглядела так:

if (Foo() && Bar())
{
    SomeProperty = true;
}
else
{
    SomeProperty = false;
}

или вот так:

if (Foo())
{
    if (Bar())
       SomeProperty = true;
    else
       SomeProperty = false;
}
else
{
    SomeProperty = false;
}

Тогда он по крайней мере будет согласованным. Таким образом, логика намного сложнее, чем второй случай.

Ответ 16

Это часто бывает полезно, чтобы быть в состоянии останова любой конкретный вызов функции по отдельности, а также какой-либо конкретной настройки переменной к определенному значению - это, возможно, спорное, я был бы склонен идти на первый вариант. Это дает больший шанс разрешить мелкозернистую точку останова для всех отладчиков (что в случае С# не очень большое число).

Таким образом, точка останова может быть установлена ​​перед вызовом Foo() перед вызовом в Bar() (и набором переменной), а когда переменной установлено значение false - и, очевидно, одни и те же точки останова может также использоваться для улавливания случаев Foo() vs! Foo(), в зависимости от вопроса, который имеет в виду.

Это невозможно сделать, если все это на одной строке, но оно привлекает внимание, которое может быть использовано для выяснения причины любой проблемы.

(С# быстро компилируется, поэтому, как правило, не является большой проблемой переупорядочить код, но это отвлекает.)

Ответ 17

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

Первый способ разъясняет случайному наблюдателю, что вы не выполняете Bar(), если Foo() не возвращает true. Я понимаю, что логика короткого замыкания будет удерживать Bar() от вызова во втором примере (и я мог бы написать ее так же сам), но первый способ гораздо более преднамерен на первый взгляд.

Ответ 18

Короткое замыкание поведения И не является стандартным для всех языков, поэтому я, как правило, опасаюсь использовать его неявно, если это необходимо для моего кода.

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

Итак, если Boo() никогда не следует вызывать, когда Foo() возвращает false, я бы пошел с версией № 2, хотя бы как защитный метод программирования.

Ответ 19

Первый метод более читабельен, но получает больше строк кодов, второй - более эффективный, без сравнения, только одна строка! Я думаю, что второй лучше

Ответ 20

Поскольку вы используете С#, я бы выбрал первую версию или использовал тернарный оператор ?:. Использование && таким образом не является общей идиомой в С#, поэтому вы, скорее всего, будете неправильно поняты. В некоторых других языках (Ruby приходит на ум) шаблон && более популярен, и я бы сказал, что он подходит в этом контексте.

Ответ 21

Я бы сказал, что код читабельен, если он читается человеку, который не знает фактического языка программирования, поэтому код вроде

if(Foo() == true and Bar() == true)
then
    SomeProperty = true;
else
    SomeProperty = false;

гораздо читабельнее, чем

SomeProperty = Foo() && Bar();

Если программист берет код после того, как вы не знакомы с последним синтаксисом, он будет стоить ему в 10 раз больше времени, затрачиваемого на запись этих лишних символов.