Чи є вагомі причини, чому кращою практикою є лише одне твердження про повернення у функції?
Або добре повертатися з функції, як тільки це логічно правильно, це означає, що у функції може бути багато тверджень про повернення?
Чи є вагомі причини, чому кращою практикою є лише одне твердження про повернення у функції?
Або добре повертатися з функції, як тільки це логічно правильно, це означає, що у функції може бути багато тверджень про повернення?
Відповіді:
У мене часто є кілька тверджень на початку способу повернутися для "легких" ситуацій. Наприклад, це:
public void DoStuff(Foo foo)
{
if (foo != null)
{
...
}
}
... можна зробити більш читабельним (IMHO), як це:
public void DoStuff(Foo foo)
{
if (foo == null) return;
...
}
Так, так, я думаю, що нормально мати кілька "точок виходу" з функції / методу.
DoStuff() { DoStuffInner(); IncreaseStuffCallCounter(); }
Ніхто не згадував і не цитував Кодекс повний, тому я це зроблю.
Мінімізуйте кількість повернень у кожній програмі . Важко зрозуміти розпорядок, якщо, читаючи його внизу, ви не знаєте про можливість того, що він повернувся десь вище.
Використовуйте віддачу, коли вона підвищує читабельність . У певних процедурах, як тільки ви дізнаєтесь відповідь, ви хочете негайно повернути її в процедуру виклику. Якщо рутина визначена таким чином, що вона не потребує очищення, не повернення негайно означає, що вам доведеться написати більше коду.
Я б сказав, було б неймовірно нерозумно приймати рішення довільно проти кількох точок виходу, оскільки я вважав, що методика корисна на практиці знову і знову , адже я часто переробляв існуючий код на кілька точок виходу для наочності. Ми можемо порівняти два підходи таким чином:
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 підбираються належним чином.
Цей метод робить обслуговування коду надзвичайно складним та схильним до помилок.
Структуроване програмування говорить, що ви повинні мати будь-коли одне твердження про повернення на функцію. Це для обмеження складності. Багато людей, таких як Мартін Фаулер, стверджують, що простіше писати функції з декількома операторами повернення. Він подає цей аргумент у написаній ним класичній книзі про рефакторинг . Це добре працює, якщо ви дотримуєтесь його інших порад і пишете невеликі функції. Я погоджуюся з цією точкою зору, і лише суворі структуровані пуристи програмування дотримуються єдиних операторів повернення на функцію.
GOTO
для переміщення потоку управління навіть тоді, коли функція існувала. Ніколи не сказано "ніколи не використовуй GOTO
".
Як зазначає Кент Бек, обговорюючи положення про охорону в "Шаблонах впровадження", що створюють звичайну процедуру, мають єдину точку входу та виходу ...
"було запобігати плутанині, можливій під час стрибків у та з багатьох місць в одному розпорядку. Це було добре, коли застосовувались до FORTRAN або мовних програм мовлення, написаних з великою кількістю глобальних даних, де навіть розуміння, які заяви виконувались, було важкою роботою." "Малі методи та здебільшого локальні дані є непотрібними".
Я знаходжу, що функцію, написану з охоронними статтями, набагато простіше виконувати, ніж один довгий вкладений набір if then else
тверджень.
У функції, яка не має побічних ефектів, немає вагомих причин мати більше, ніж одне повернення, і ви повинні писати їх у функціональному стилі. У методі з побічними ефектами все є більш послідовним (індексованим часом), тому ви пишете в імперативному стилі, використовуючи оператор return як команду для припинення виконання.
Іншими словами, коли це можливо, надайте перевагу цьому стилю
return a > 0 ?
positively(a):
negatively(a);
над цим
if (a > 0)
return positively(a);
else
return negatively(a);
Якщо ви виявите, що ви пишете кілька шарів вкладених умов, мабуть, ви зможете переробити це, використовуючи, наприклад, список предикатів. Якщо ви виявите, що ваші ifs і elses синтаксично розставлені, ви можете розбити це на більш дрібні функції. Умовний блок, який охоплює більше екранного тексту, важко читати.
Не існує жодного жорсткого і швидкого правила, яке стосується кожної мови. Щось на кшталт наявності єдиної заяви про повернення не зробить ваш код хорошим. Але хороший код, як правило, дозволяє вам писати свої функції таким чином.
Я бачив це в стандартах кодування для C ++, які перестали працювати з C, як якщо б у вас немає RAII або іншого автоматичного управління пам'яттю, тоді вам потрібно очищати кожне повернення, що означає "вирізати і вставити" очищення або гото (логічно те саме, що "нарешті" в керованих мовах), обидва вони вважаються поганою формою. Якщо ваша практика полягає у використанні розумних покажчиків та колекцій у C ++ або іншій автоматичній системі пам’яті, то для цього немає вагомих причин, і це стає все для читабельності та більше виклику судження.
auto_ptr
, ви можете паралельно використовувати звичайні покажчики. Хоча було б дивно писати «оптимізований» код з неоптимізуючим компілятором в першу чергу.
try
... finally
на Java), і вам потрібно виконати обслуговування ресурсів, яке ви могли б зробити з одним повернення в кінці методу. Перш ніж зробити це, слід серйозно подумати про рефакторинг коду, щоб позбутися від ситуації.
Я схиляюся до думки, що повернення тверджень посеред функції погані. Ви можете використовувати віддачі для створення декількох застережних застережень у верхній частині функції, і, звичайно, скажіть компілятору, що потрібно повернути в кінці функції без проблем, але повернення в середині функції можна легко пропустити і можна ускладнюють інтерпретацію функції.
Чи є вагомі причини, чому кращою практикою є лише одне твердження про повернення у функції?
Так , є:
Питання часто задається помилковою дихотомією між декількома поверненнями або глибоко вкладеними у висловлюваннях. Майже завжди є третє рішення, яке є дуже лінійним (без глибокого гніздування) лише з однією точкою виходу.
Оновлення : Очевидно, вказівки MISRA також сприяють одному виходу .
Щоб було зрозуміло, я не кажу, що завжди неправильно мати кілька повернень. Але з огляду на рівнозначні рішення, є багато вагомих причин віддати перевагу тому, що має єдину віддачу.
Contract.Ensures
з декількома точками повернення.
goto
для переходу до загального коду очищення, ви, ймовірно, спростили функцію, щоб return
в кінці коду очищення був один. Отже, ви можете сказати, що ви вирішили проблему goto
, але я б сказав, що ви вирішили її, спростивши до єдиної return
.
Наявність єдиної точки виходу дає перевагу при налагодженні, оскільки дозволяє встановити єдину точку розриву в кінці функції, щоб побачити, яке значення насправді буде повернуто.
Взагалі я намагаюся мати лише одну точку виходу з функції. Однак бувають випадки, що це фактично закінчується створенням більш складного функціонального тіла, ніж це необхідно, і в цьому випадку краще мати кілька точок виходу. Це дійсно має бути "викликом судження", що базується на отриманій складності, але метою повинно бути якомога менше вихідних точок без шкоди для складності та зрозумілості.
Ні, тому що ми вже не живемо в 1970-х . Якщо ваша функція досить довга, що кілька разів повернення є проблемою, вона занадто довга.
(Цілком крім того, що будь-яка багаторядкова функція на мові з винятками все одно матиме декілька точок виходу.)
Я вважаю за краще один вихід, якщо це дійсно не ускладнює речі. Я виявив, що в деяких випадках кілька існуючих точок можуть маскувати інші більш значні проблеми дизайну:
public void DoStuff(Foo foo)
{
if (foo == null) return;
}
Побачивши цей код, я одразу попрошу:
Залежно від відповідей на ці запитання, це може бути саме так
В обох вищезазначених випадках код, ймовірно, може бути перероблений із твердженням, щоб переконатися, що "foo" ніколи не буває нульовим, а відповідні абоненти змінені.
Є дві інші причини (конкретні, я думаю, для коду С ++), коли існує декілька, насправді можуть мати негативний вплив. Вони мають розмір коду та оптимізацію компілятора.
Об'єкт, який не є POD C ++ в області дії на виході з функції, матиме назву деструктора. Якщо є кілька тверджень про повернення, можливо, в обсягах існують різні об'єкти, тому список деструкторів, які потрібно викликати, буде різним. Тому компілятору необхідно генерувати код для кожного оператора return:
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'
}
Якщо розмір коду є проблемою - то цього, можливо, варто чогось уникати.
Інший випуск стосується "Оптимізації іменованого повернення значення" (він же Copy 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 дозволяє компілятору сконструювати "a1" там же, що знаходиться на стеку, як "a2". Тому немає необхідності "копіювати" об'єкт, коли функція повертається.
Кілька точок виходу ускладнює роботу компілятора в спробі виявити це, і принаймні для відносно недавньої версії VC ++ оптимізація не відбулася там, де тіло функції мало кілька повернень. Докладніші відомості див. У розділі Оптимізація іменованого значення повернення у Visual C ++ 2005 .
throw new ArgumentNullException()
в C # в даному випадку), мені дуже сподобалися ваші інші міркування, вони для мене справедливі і можуть бути критичними в деяких нішеві контексти.
foo
тестують, не має нічого спільного з темою, що потрібно робити, if (foo == NULL) return; dowork;
абоif (foo != NULL) { dowork; }
Наявність єдиної точки виходу зменшує цикломатичну складність і, отже, теоретично , зменшує ймовірність того, що ви внесете помилки у свій код, коли ви його зміните. Однак практика показує, що потрібен більш прагматичний підхід. Тому я схильний прагнути мати одну точку виходу, але дозволяю моєму коду мати декілька, якщо це є більш читабельним.
Я змушую себе використовувати лише одне 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.
Не існує закону, який вимагав би лише однієї точки виходу для методу на всіх мовах програмування . Деякі люди наполягають на перевазі цього стилю, а іноді вони підносять його до "правила" чи "закону", але ця віра не підкріплена жодними доказами чи дослідженнями.
Більше одного стилю повернення може бути шкідливою звичкою в коді С, де ресурси мають бути явно розмежовані, але такі мови, як Java, C #, Python або JavaScript, мають такі конструкції, як автоматичне збирання сміття та try..finally
блоки (іusing
блоки в C # ), і цей аргумент не застосовується - у цих мовах дуже рідко потрібна централізована ручна розробка ресурсів.
Бувають випадки, коли одне повернення є більш читабельним, і випадки, коли його немає. Перевірте, чи зменшує вона кількість рядків коду, робить логіку зрозумілішою чи зменшує кількість дужок та відступів або тимчасових змінних.
Тому використовуйте стільки повернень, скільки відповідає вашим художнім почуттям, адже це питання компонування та читабельності, а не технічна.
Я говорив про це більш детально у своєму блозі .
Про те, що єдина точка виходу, можна сказати так само, як і погані речі про неминуче програмування «стрілки» .
Якщо під час перевірки вводу чи розподілу ресурсів використовуються декілька точок виходу, я намагаюся помітити всі «виходи помилки» дуже помітно вгорі функції.
У статті про спартанське програмування "SSDSLPedia" та статті про єдину функцію виходу "Вікісховища Портлендського візерунка" є деякі проникливі аргументи щодо цього. Також, звичайно, є ця посада для розгляду.
Якщо ви дійсно хочете отримати єдину точку виходу (будь-якою мовою, що не включає виняток), наприклад, щоб вивільнити ресурси в одному місці, я вважаю, що ретельне застосування 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, скопійованому зверху, питання полягає в тому, що відбувається в // Rest of code ... ?:
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;
}
null
замість того, щоб кидати виняток із зазначенням, що аргумент не прийнятий?
Однією з вагомих причин я можу придумати це підтримка коду: у вас єдина точка виходу. Якщо ви хочете змінити формат результату, ..., це просто набагато простіше здійснити. Також для налагодження можна просто наклеїти там точку зламу :)
Сказавши це, мені одного разу довелося працювати в бібліотеці, де стандарти кодування нав'язували "одне повернення на функцію", і мені здалося, що це досить важко. Я пишу безліч числових кодів обчислень, і часто трапляються "особливі випадки", тому код в кінцевому підсумку досить важко слідувати ...
Кілька точок виходу добре підходять для досить малих функцій - тобто функції, яку можна переглядати по одній довжині екрана в повному обсязі. Якщо тривала функція також включає кілька точок виходу, це знак того, що функцію можна порубати далі.
Це означає, що я уникаю функцій багаторазового виходу, якщо це абсолютно не потрібно . Я відчув біль від помилок, який пояснюється деяким бродячим поверненням в якусь незрозумілу лінію при більш складних функціях.
Я працював із жахливими стандартами кодування, які змусили вас пройти єдиний шлях виходу, і результат майже завжди є неструктурованим спагетті, якщо функція є не що інше, але тривіальна - ви закінчуєте безліч перерв і продовжуєте це просто заважати.
if
заяву перед кожним викликом методу, який повертає успіх чи ні :(
Одинарна точка виходу - всі інші речі рівні - робить код значно читабельнішим. Але є улов: популярне будівництво
resulttype res;
if if if...
return res;
є підробкою, "res =" не набагато краще, ніж "повернення". У ньому є одне твердження про повернення, але кілька точок, де функція фактично закінчується.
Якщо у вас функція з декількома поверненнями (або "res =" s), часто корисно розбити її на кілька менших функцій з однією точкою виходу.
Моя звичайна політика полягає в тому, щоб в кінці функції було лише одне твердження повернення, якщо складність коду значно не зменшується додаванням більше. Насправді я скоріше шанувальник Ейфеля, який застосовує єдине правило повернення, не маючи заяви про повернення (для створення результату є лише створена автоматично автоматична змінна "результат").
Безумовно, є випадки, коли код може бути зрозумілішим з декількома поверненнями, ніж очевидна версія без них. Можна стверджувати, що потрібно більше переробляти, якщо у вас є надто складна функція, щоб її було зрозуміло без багаторазових зворотних заяв, але іноді добре бути прагматичним щодо таких речей.
Якщо ви отримаєте більше, ніж кілька повернень, з вашим кодом може статися щось не так. Інакше я погоджуюся, що іноді приємно мати можливість повертатися з декількох місць підпрограми, особливо коли це робить код чистішим.
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 }
}
}
краще писати так
@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);
}
}
Це, мабуть, незвична перспектива, але я вважаю, що тому, хто вважає, що потрібно віддавати кілька заяв про повернення, ніколи не доводилося використовувати налагоджувач на мікропроцесорі, який підтримує лише 4 апаратних точки прориву. ;-)
Хоча проблеми "коду стрілки" повністю коректні, одна проблема, яка, здається, усунеться при використанні декількох операторів повернення, знаходиться в ситуації, коли ви використовуєте відладчик. Ви не маєте зручного положення для лову, щоб поставити точку перелому, щоб гарантувати, що ви збираєтесь побачити вихід, а отже, і стан повернення.
Чим більше висловлювань повернення у вас у функції, тим вище складність цього методу. Якщо вам цікаво, чи є у вас занадто багато зворотних заяв, ви можете запитати себе, чи є у вас занадто багато рядків коду в цій функції.
Але, ні, в одному / безлічі зворотних заяв немає нічого поганого. У деяких мовах це краща практика (C ++), ніж в інших (C).