Це поняття Single Entry, Single Exit (SESE) походить з мов із чітким керуванням ресурсами , як, наприклад, C та зборка. У З таким кодом буде витікати ресурси:
void f()
{
resource res = acquire_resource(); // think malloc()
if( f1(res) )
return; // leaks res
f2(res);
release_resource(res); // think free()
}
У таких мовах у вас є три варіанти:
Повторіть код очищення.
Тьфу. Надлишок завжди поганий.
Використовуйте a, goto
щоб перейти до коду очищення.
Для цього потрібен код очищення як останнє в функції. (І тому деякі стверджують, що goto
має своє місце. І це справді - в C.)
Введіть локальну змінну та маніпулюйте потоком управління через це.
Недоліком є те, що управління потоком маніпулюють з допомогою синтаксису (думаю break
, return
, if
, while
) набагато легше стежити , ніж потік управління маніпулюють через стан змінних (оскільки ці змінні не мають стану , коли ви дивитеся на алгоритмі).
У монтажі це ще більш дивно, тому що ви можете переходити на будь-яку адресу функції, коли ви викликаєте цю функцію, що фактично означає, що у вас є майже необмежена кількість вхідних точок до будь-якої функції. (Іноді це корисно. Такі гроти - це поширена техніка для компіляторів для здійснення this
коригування вказівника, необхідного для виклику virtual
функцій у сценаріях множинного успадкування в C ++.)
Коли вам доведеться керувати ресурсами вручну, використання параметрів введення або виходу з функції в будь-якому місці призводить до більш складного коду і, отже, до помилок. Тому з’явилася школа думки, яка поширює SESE, щоб отримати більш чистий код та менше помилок.
Однак, коли в мові є винятки, (майже) будь-яка функція може бути запущена передчасно (майже) в будь-якій точці, тому потрібно все-таки передбачити умови для передчасного повернення. (Я думаю finally
, що використовується в основному для цього в Java та using
(при впровадженні IDisposable
, finally
інакше) в C #; C ++ замість цього використовується RAII .) Після цього ви не зможете не прибрати очищення після себе через раннє return
твердження, так що, ймовірно, найсильніший аргумент на користь SESE зник.
Це залишає читабельність. Звичайно, функція 200 LoC з півдюжиною return
висловлювань, випадковим чином розсипається над нею, не є гарним стилем програмування і не робить для читабельного коду. Але таку функцію було б легко зрозуміти і без цих передчасних повернень.
У мовах, де ресурсами не слід керувати або не слід керувати ними вручну, мало дотримується старої конвенції SESE або її немає. Як я вже заперечував, OTOH, часто SESE робить код складнішим . Це динозавр, який (за винятком С) не добре вписується в більшість сучасних мов. Замість того, щоб допомагати зрозумілості коду, він перешкоджає цьому.
Чому програмісти Java дотримуються цього? Я не знаю, але від моєї (ззовні) POV, Java взяла багато конвенцій від C (де вони мають сенс) і застосувала їх до свого OO світу (де вони марні чи відверто погані), де зараз це дотримується їх, незалежно від витрат. (Як і угода про визначення всіх змінних на початку області.)
Програмісти дотримуються всіляких дивних позначень з нераціональних причин. (Глибоко вкладені структурні висловлювання - «наконечники стріл» - колись розглядалися як прекрасний код на мовах, таких як Паскаль.) Застосування чистого логічного міркування до цього, здається, не може переконати більшість із них відхилитися від встановлених ними способів. Найкращий спосіб змінити такі звички - це, мабуть, навчити їх рано робити те, що найкраще, а не те, що є звичайним. Ви, будучи викладачем програмування, маєте це в руці.:)