Должна ли функция иметь только одну инструкцию возврата?

Есть ли веские причины, по которым лучше иметь в функции только один оператор return?

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

50 ответов

Решение

У меня часто есть несколько утверждений в начале метода, чтобы вернуться к "легким" ситуациям. Например, это:

public void DoStuff(Foo foo)
{
    if (foo != null)
    {
        ...
    }
}

... можно сделать более читабельным (ИМХО) следующим образом:

public void DoStuff(Foo foo)
{
    if (foo == null) return;

    ...
}

Так что да, я думаю, что хорошо иметь несколько "точек выхода" из функции / метода.

Никто не упоминал и не цитировал Code Complete, поэтому я сделаю это.

17.1 возврат

Минимизируйте количество возвратов в каждой процедуре. Труднее понять рутину, если, читая ее внизу, вы не подозреваете о возможности ее возвращения где-то выше.

Используйте возврат, когда он улучшает читабельность. В некоторых подпрограммах, когда вы знаете ответ, вы хотите немедленно вернуть его в вызывающую подпрограмму. Если подпрограмма определена таким образом, что она не требует какой-либо очистки, то немедленный возврат означает, что вам нужно написать больше кода.

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

string fooBar(string s, int? i) {
  string ret = "";
  if(!string.IsNullOrEmpty(s) && i != null) {
    var res = someFunction(s, i);

    bool passed = true;
    foreach(var r in res) {
      if(!r.Passed) {
        passed = false;
        break;
      }
    }

    if(passed) {
      // Rest of code...
    }
  }

  return ret;
}

Сравните это с кодом, где разрешено несколько точек выхода:

string fooBar(string s, int? i) {
  var ret = "";
  if(string.IsNullOrEmpty(s) || i == null) return null;

  var res = someFunction(s, i);

  foreach(var r in res) {
      if(!r.Passed) return null;
  }

  // Rest of code...

  return ret;
}

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

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

С теорией "единой точки выхода" вы неизбежно столкнетесь с кодом, который выглядит следующим образом:

function()
{
    HRESULT error = S_OK;

    if(SUCCEEDED(Operation1()))
    {
        if(SUCCEEDED(Operation2()))
        {
            if(SUCCEEDED(Operation3()))
            {
                if(SUCCEEDED(Operation4()))
                {
                }
                else
                {
                    error = OPERATION4FAILED;
                }
            }
            else
            {
                error = OPERATION3FAILED;
            }
        }
        else
        {
            error = OPERATION2FAILED;
        }
    }
    else
    {
        error = OPERATION1FAILED;
    }

    return error;
}

Мало того, что это делает код очень трудным для отслеживания, но теперь скажем, что вам нужно вернуться назад и добавить операцию между 1 и 2. Вы должны сделать отступ практически для всей функции, и удачи, убедившись, что все Ваши условия if/else и фигурные скобки сопоставлены должным образом.

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

Структурированное программирование говорит, что вы должны иметь только один оператор возврата для каждой функции. Это для ограничения сложности. Многие люди, такие как Мартин Фаулер, утверждают, что проще писать функции с несколькими операторами возврата. Он представляет этот аргумент в классической книге рефакторинга, которую он написал. Это хорошо работает, если вы будете следовать его другим советам и писать небольшие функции. Я согласен с этой точкой зрения, и только пуристы строгого структурированного программирования придерживаются единственного оператора return для каждой функции.

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

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

Я считаю, что функцию, написанную с помощью охранных предложений, гораздо проще выполнять, чем одну длинную вложенную группу if then else заявления.

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

Другими словами, по возможности, поддерживайте этот стиль

return a > 0 ?
  positively(a):
  negatively(a);

через это

if (a > 0)
  return positively(a);
else
  return negatively(a);

Если вы обнаружите, что пишете несколько слоев вложенных условий, возможно, есть способ реорганизовать их, например, используя список предикатов. Если вы обнаружите, что ваши if и elses синтаксически далеко друг от друга, вы можете разбить это на более мелкие функции. Условный блок, который занимает больше, чем экранный текст, трудно читать.

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

Я видел это в стандартах кодирования для C++, которые были похмелье от C, как будто у вас нет RAII или другого автоматического управления памятью, тогда вы должны очищать для каждого возврата, что либо означает вырезать и вставить очистки или перехода (логически то же самое, что "наконец" в управляемых языках), оба из которых считаются дурным тоном. Если вы практикуете использование умных указателей и коллекций в C++ или другой автоматической системе памяти, то для этого нет веских оснований, и все сводится к удобочитаемости и, скорее, к суждению.

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

Есть ли веские причины, по которым лучше иметь в функции только один оператор return?

Да, есть:

  • Единая точка выхода дает отличное место для утверждения ваших постусловий.
  • Возможность поставить точку останова отладчика на один возврат в конце функции часто бывает полезна.
  • Меньше возвратов означает меньшую сложность. Линейный код, как правило, проще для понимания.
  • Если попытка упростить функцию до одного возврата вызывает сложность, то это является стимулом для рефакторинга в более мелкие, более общие и понятные функции.
  • Если вы говорите на языке без деструкторов или не используете RAII, то один возврат сокращает количество мест, которые вы должны очистить.
  • Некоторые языки требуют единой точки выхода (например, Pascal и Eiffel).

Вопрос часто ставится как ложная дихотомия между множественными возвратами или глубоко вложенными операторами if. Почти всегда существует третье решение, которое является очень линейным (без глубокого вложения) с единственной точкой выхода.

Обновление: очевидно, руководящие принципы MISRA также предусматривают единый выход.

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

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

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

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

(Совершенно независимо от того факта, что любая многострочная функция в языке с исключениями в любом случае будет иметь несколько точек выхода.)

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

public void DoStuff(Foo foo)
{
    if (foo == null) return;
}

Увидев этот код, я бы сразу спросил:

  • Является ли 'foo' когда-либо нулевым?
  • Если так, сколько клиентов DoStuff когда-либо вызывали функцию с нулевым значением 'foo'?

В зависимости от ответов на эти вопросы может быть

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

В обоих вышеупомянутых случаях код, вероятно, может быть переработан с утверждением, гарантирующим, что 'foo' никогда не будет нулевым, а соответствующие вызывающие абоненты изменены.

Есть две другие причины (которые, я думаю, специфичны для кода C++), когда множественность существует, может оказать негативное влияние Это размер кода и оптимизация компилятора.

У не-POD C++ объекта в области видимости при выходе из функции будет вызван деструктор. Там, где есть несколько операторов возврата, это может быть случай, когда существуют разные объекты в области видимости, поэтому список вызываемых деструкторов будет другим. Поэтому компилятор должен генерировать код для каждого оператора возврата:

void foo (int i, int j) {
  A a;
  if (i > 0) {
     B b;
     return ;   // Call dtor for 'b' followed by 'a'
  }
  if (i == j) {
     C c;
     B b;
     return ;   // Call dtor for 'b', 'c' and then 'a'
  }
  return 'a'    // Call dtor for 'a'
}

Если размер кода является проблемой, то этого стоит избегать.

Другая проблема связана с "Оптимизацией именованных возвращаемых значений" (также известной как "Копия Elision", ISO C++ '03 12.8/15). C++ позволяет реализации пропустить вызов конструктора копирования, если он может:

A foo () {
  A a1;
  // do something
  return a1;
}

void bar () {
  A a2 ( foo() );
}

Просто принимая код как есть, объект "a1" создается в "foo", и затем вызывается его конструкция копирования для создания "a2". Однако, elision copy позволяет компилятору создавать "a1" в том же месте в стеке, что и "a2". Поэтому нет необходимости "копировать" объект, когда функция возвращается.

Многочисленные точки выхода усложняют работу компилятора при попытке обнаружить это, и, по крайней мере, для сравнительно недавней версии VC++ оптимизация не имела места, когда тело функции имело несколько возвращений. Посмотрите Оптимизацию Именованного Возвращаемого значения в Visual C++ 2005 для получения дополнительной информации.

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

Я заставляю себя использовать только один return заявление, поскольку это будет в некотором смысле генерировать запах кода. Позволь мне объяснить:

function isCorrect($param1, $param2, $param3) {
    $toret = false;
    if ($param1 != $param2) {
        if ($param1 == ($param3 * 2)) {
            if ($param2 == ($param3 / 3)) {
                $toret = true;
            } else {
                $error = 'Error 3';
            }
        } else {
            $error = 'Error 2';
        }
    } else {
        $error = 'Error 1';
    }
    return $toret;
}

(Условия являются произвольными...)

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

  • Несколько возвратов
  • Рефакторинг на отдельные функции

Многократный возврат

function isCorrect($param1, $param2, $param3) {
    if ($param1 == $param2)       { $error = 'Error 1'; return false; }
    if ($param1 != ($param3 * 2)) { $error = 'Error 2'; return false; }
    if ($param2 != ($param3 / 3)) { $error = 'Error 3'; return false; }
    return true;
}

Отдельные функции

function isEqual($param1, $param2) {
    return $param1 == $param2;
}

function isDouble($param1, $param2) {
    return $param1 == ($param2 * 2);
}

function isThird($param1, $param2) {
    return $param1 == ($param2 / 3);
}

function isCorrect($param1, $param2, $param3) {
    return !isEqual($param1, $param2)
        && isDouble($param1, $param3)
        && isThird($param2, $param3);
}

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

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

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

Я лично никогда не слышал / не видел, чтобы "лучшие практики" говорили, что у вас должно быть только одно ответное заявление.

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

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

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

Более чем один стиль возврата может быть плохой привычкой в ​​коде C, где ресурсы должны быть явно выделены, но такие языки, как Java, C#, Python или JavaScript, имеют такие конструкции, как автоматическая сборка мусора и try..finally блоки (и using блоки в C#), и этот аргумент неприменим - в этих языках очень редко требуется централизованное ручное освобождение ресурсов.

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

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

Я говорил об этом более подробно в своем блоге.

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

Если при проверке входных данных или распределении ресурсов используются несколько точек выхода, я стараюсь очень четко поместить все "выходы с ошибками" в верхнюю часть функции.

Как в статье о спартанском программировании "SSDSLPedia", так и в статье о точках выхода из одной функции "Wiki репозитория шаблонов Portland" есть несколько проницательных аргументов. Также, конечно, есть этот пост для рассмотрения.

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

int f(int y) {
    int value = -1;
    void *data = NULL;

    if (y < 0)
        goto clean;

    if ((data = malloc(123)) == NULL)
        goto clean;

    /* More code */

    value = 1;
clean:
   free(data);
   return value;
}

Лично я вообще не люблю программирование стрелок больше, чем несколько точек выхода, хотя обе они полезны при правильном применении. Лучше всего, конечно, структурировать вашу программу, чтобы не требовалось ни того, ни другого. Разбиение вашей функции на несколько частей обычно помогает:)

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

int g(int y) {
  value = 0;

  if ((value = g0(y, value)) == -1)
    return -1;

  if ((value = g1(y, value)) == -1)
    return -1;

  return g2(y, value);
}

В зависимости от проекта или руководящих принципов кодирования большая часть кода котельной плиты может быть заменена макросами. В качестве примечания, если разбить его таким образом, функции g0, g1,g2 очень легко тестировать по отдельности.

Очевидно, что в языке OO и с поддержкой исключений я бы не использовал подобные операторы if (или вообще, если бы мне это удавалось без особых усилий), и код был бы намного более простым. И без стрелок. И большинство не окончательных результатов, вероятно, будут исключениями.

Короче;

  • Немногие возвраты лучше многих
  • Более одного возврата лучше, чем огромные стрелы, и пункты охраны обычно в порядке.
  • Исключения могут / должны, вероятно, заменить большинство "охранных положений", когда это возможно.

Вы знаете пословицу - красота в глазах смотрящего.

Некоторые люди клянутся NetBeans, а некоторые IntelliJ IDEA, некоторые Python, а некоторые PHP.

В некоторых магазинах вы можете потерять работу, если будете настаивать на этом:

public void hello()
{
   if (....)
   {
      ....
   }
}

Все дело в наглядности и удобстве обслуживания.

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

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

Я помню, как 20 лет назад мой коллега был уволен за использование того, что сегодня будет называться стратегией гибкого развития. У него был дотошный пошаговый план. Но его менеджер кричал на него: "Вы не можете постепенно предоставлять функции пользователям! Вы должны придерживаться водопада". Он ответил менеджеру, что постепенное развитие будет более точным в соответствии с потребностями клиента. Он верил в разработку для нужд клиентов, но менеджер верил в кодирование по "требованию клиента".

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

Лично я считаю, что PHP - плохая практика, но что я знаю. Все теоретические аргументы сводятся к попыткам выполнить один набор правил

качество = точность, ремонтопригодность и рентабельность.

Все остальные правила отходят на второй план. И, конечно, это правило никогда не исчезает:

Лень - это добродетель хорошего программиста.

Я склоняюсь к использованию пунктов охраны, чтобы вернуться рано и иначе выйти в конце метода. Единственное правило входа и выхода имеет историческое значение и было особенно полезно при работе с устаревшим кодом, который занимал до 10 страниц формата А4 для одного метода C++ с множественными возвратами (и многими дефектами). В последнее время общепринятой практикой является сохранение небольших методов, что делает множественные выходы менее значительными для понимания. В следующем примере Kronoz, скопированном выше, вопрос в том, что происходит в // Остальном коде...?:

void string fooBar(string s, int? i) {

  if(string.IsNullOrEmpty(s) || i == null) return null;

  var res = someFunction(s, i);

  foreach(var r in res) {
      if(!r.Passed) return null;
  }

  // Rest of code...

  return ret;
}

Я понимаю, что пример несколько надуманный, но у меня возникнет соблазн реорганизовать цикл foreach в оператор LINQ, который затем можно будет рассматривать как защитное предложение. Опять же, в надуманном примере цель кода не очевидна, и у someFunction() может быть какой-то другой побочный эффект, или результат может быть использован в // Остальном коде....

if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;

Предоставление следующей рефакторированной функции:

void string fooBar(string s, int? i) {

  if (string.IsNullOrEmpty(s) || i == null) return null;
  if (someFunction(s, i).Any(r => !r.Passed)) return null;

  // Rest of code...

  return ret;
}

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

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

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

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

Единая точка выхода - при прочих равных условиях - делает код значительно более читабельным. Но есть подвох: популярная конструкция

resulttype res;
if if if...
return res;

подделка, "res=" не намного лучше, чем "возврат". Он имеет один оператор возврата, но несколько точек, где функция фактически заканчивается.

Если у вас есть функция с несколькими возвратами (или "res="s), часто неплохо разбить ее на несколько более мелких функций с одной точкой выхода.

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

Моя обычная политика - иметь только один оператор return в конце функции, если сложность кода не будет значительно уменьшена путем добавления большего количества. На самом деле, я скорее поклонник Eiffel, который применяет единственное правило возврата, не имея оператора return (есть просто автоматически созданная переменная 'result', в которую можно поместить ваш результат).

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

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

Perl 6: плохой пример

sub Int_to_String( Int i ){
  given( i ){
    when 0 { return "zero" }
    when 1 { return "one" }
    when 2 { return "two" }
    when 3 { return "three" }
    when 4 { return "four" }
    ...
    default { return undef }
  }
}

было бы лучше написать так

Perl 6: хороший пример

@Int_to_String = qw{
  zero
  one
  two
  three
  four
  ...
}
sub Int_to_String( Int i ){
  return undef if i < 0;
  return undef unless i < @Int_to_String.length;
  return @Int_to_String[i]
}

Обратите внимание, что это был только быстрый пример

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

void ProcessMyFile (char *szFileName)
{
   FILE *fp = NULL;
   char *pbyBuffer = NULL:

   do {

      fp = fopen (szFileName, "r");

      if (NULL == fp) {

         break;
      }

      pbyBuffer = malloc (__SOME__SIZE___);

      if (NULL == pbyBuffer) {

         break;
      }

      /*** Do some processing with file ***/

   } while (0);

   if (pbyBuffer) {

      free (pbyBuffer);
   }

   if (fp) {

      fclose (fp);
   }
}

Вероятно, это необычная перспектива, но я думаю, что любому, кто считает, что нужно использовать несколько операторов return, никогда не приходилось использовать отладчик на микропроцессоре, который поддерживает только 4 аппаратных точки останова.;-)

Хотя проблемы с "кодом стрелки" полностью верны, одна проблема, которая, похоже, исчезает при использовании нескольких операторов return, - это ситуация, когда вы используете отладчик. У вас нет удобной универсальной позиции для установки точки останова, чтобы гарантировать, что вы увидите выход и, следовательно, условие возврата.

Если можно записать только мнение, это мое:

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

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

Функция (если это действительно функция / запрос согласно примечанию `Разделение запросов-команд '- см., Например, язык программирования Eiffel) просто ДОЛЖНА определить столько точек возврата, сколько имеется в сценариях потока управления. Это намного более ясно и математически последовательно; и это способ писать функции (например, запросы)

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

Другие вопросы по тегам