Какой код более читабелен? - PullRequest
32 голосов
/ 09 октября 2009

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

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

или

SomeProperty = Foo() && Bar();

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

Что вы думаете? Есть ли другие факторы, которые влияют на решение? Например, если выражение && длиннее, чем одна строка, которая может уместиться на экране, я должен предпочесть первое?


Пояснения после ответа:

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

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

Ответы [ 21 ]

93 голосов
/ 09 октября 2009

Я согласен с общим мнением, что форма 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();

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

45 голосов
/ 09 октября 2009

Мне нравится эта сокращенная запись, если ваш язык позволяет это:

SomeProperty = Foo() ? Bar() : false;
19 голосов
/ 09 октября 2009
SomeProperty = Foo() && Bar();

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

SomeProperty = 
   Foo() && Bar();

      -or-

SomeProperty = Foo() && 
               Bar();

Это едва ли вредит читабельности и пониманию ИМХО.

13 голосов
/ 09 октября 2009

Зависит от того, что делают Фу и Бар.

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

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

9 голосов
/ 09 октября 2009

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

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

IsFather = IsParent() && IsMale();

и

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

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

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

6 голосов
/ 09 октября 2009

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

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

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

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

5 голосов
/ 09 октября 2009

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

4 голосов
/ 09 октября 2009

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

3 голосов
/ 09 октября 2009

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

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

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

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

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

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

...