Почему функция должна иметь только одну точку выхода?

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

Я думал, что это связано с CS, но этот вопрос был сбит в cstheory stackexchange.

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

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

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

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

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

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

   if (! argument) // Проверяем, не имеет ли значение null
     return ERR_NULL_ARGUMENT;
   ... обрабатывать непустые аргументы
   if (ok)
     return 0;
   еще
     return ERR_NOT_OK;

яснее, чем:

   int return_value;
   if (аргумент) // Non-null
   {
     .. обрабатывать непустые аргументы
     .. установить результат соответствующим образом
   }
   еще
     result = ERR_NULL_ARGUMENT;
   результат возврата;

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

Если вам кажется, что вам нужно несколько точек выхода в функции, функция слишком велика и делает слишком много.

Я бы рекомендовал прочитать главу о функциях в книге Роберта К. Мартина «Чистый код».

По сути, вы должны попытаться написать функции с 4 строками кода или меньше.

Некоторые заметки из блога Майка Лонга :

  • Первое правило функций: они должны быть небольшими
  • Второе правило функций: они должны быть меньше, чем
  • Блоки внутри операторов if, в то время как операторы, для циклов и т. Д. Должны иметь длину одной строки
  • … и эта строка кода обычно будет вызовом функции
  • Должно быть не более одного или двух уровней отступов
  • Функции должны делать одно дело
  • Операторы функций должны быть на одном уровне абстракции
  • Функция должна иметь не более 3 аргументов
  • Выходные аргументы – это запах кода
  • Передача булевского флага в функцию действительно ужасна. Вы по определению выполняете две функции в функции.
  • Побочные эффекты – это ложь.

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

С большинством всего, это сводится к потребностям поставляемого. В «старые времена» код спагетти с несколькими точками возврата вызывал утечки памяти, поскольку кодеры, которые предпочитали этот метод, обычно не хорошо очищались. Также возникали проблемы с некоторыми компиляторами, «теряющими» ссылку на возвращаемую переменную, поскольку стек был выбит во время возврата, в случае возврата из вложенной области. Более общая проблема заключалась в одном из кода повторного входа, который пытается иметь состояние вызова функции точно так же, как и его возвращаемое состояние. Мутаторы oop нарушили это, и концепция была отложена.

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

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

– 2 цента

Дополнительную информацию см. В этом документе: NISTIR 5459

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

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

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

Если студент, вы хотите заработать верхние оценки в своем classе. Делайте то, что предпочитает преподаватель. Вероятно, у него есть хорошая причина с его точки зрения; поэтому, по крайней мере, вы узнаете его точку зрения. Это само по себе имеет ценность.

Удачи.

Я был сторонником стиля с одним выходом. Мои рассуждения были в основном от боли …

Одиночный выход легче отлаживать.

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

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

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

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

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

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

Interesting Posts

Как удаленное выключение компьютера win XP из Linux?

Почему именно мне нужен явный upcast при реализации QueryInterface () в объекте с несколькими интерфейсами ()

Почему я не могу создать высоту div на 100%, если я использую HTML-тип? Как получить 100% высоту

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

Восстановление несохраненных файлов блокнота

Удалите файлы, рекурсивно соответствующие имени в командной строке (OS X)

Как обрабатывать MaxUploadSizeExceededException

Разделение файла обеспечивает какое-то шифрование?

Как я могу изменить свой брандмауэр BIOS?

Что такое алгоритм Hi / Lo?

Сделайте IE для кэширования ресурсов, но всегда проверяйте

Как узнать тип объекта (в Swift)?

Как быстро переместить текущее окно на другой вид задачи / рабочего стола в Windows 10?

escapeshellarg () отключен по соображениям безопасности

SmtpException: невозможно прочитать данные из транспортного соединения: net_io_connectionclosed

Давайте будем гением компьютера.