Jest zasadą stylu kodowania - np. Zasadą pojedynczego wyjścia
Ludzie, którzy wciąż zastanawiają się, czy wybrać jedno wyjście, czy wiele wyjść, wciąż utknęli pod koniec lat sześćdziesiątych. Wówczas taka dyskusja była ważna, ponieważ byliśmy w początkowej fazie ustrukturyzowanego programisty, a obóz głosił, że ustalenia stojące za twierdzeniem o programie strukturalnym Bohm-Jacopini nie były uniwersalne dla wszystkich konstrukcji programistycznych.
Jest to coś, co powinno być uregulowane dawno temu. Cóż, zostało to ustalone (dokładnie 4 dekady, zarówno w środowisku akademickim, jak i w branży), ale ludzie (ci, którzy są absolutnie za lub przeciw) nie zwracają na to uwagi.
Co do reszty moich odpowiedzi, wszystko jest względne (czego nie ma w oprogramowaniu?):
Tak. Przez większość czasu na ogólny przypadek, z zastrzeżeniami specyficznymi dla przypadków skrajnych i konstrukcjami programistycznymi specyficznymi dla języka.
Zawsze czy tylko czasami?
Większość czasu.
Ile to naprawdę robi różnicę?
Zależy.
Czytelny kod a nieczytelny kod. Zwiększona złożoność (którą powinniśmy już wiedzieć, zwiększa prawdopodobieństwo wprowadzenia błędów) w porównaniu z prostszą złożonością (i ergo, mniejsze prawdopodobieństwo błędów.) Języki, których kompilatory nie dodają ukrytego zwrotu (powiedzmy, Pascal, Java lub C #) i te, które domyślnie int (C i C ++).
Ostatecznie jest to umiejętność doskonalona przez liczbę godzin pracy za klawiaturą. Czasami dobrze jest mieć wiele instrukcji return, takich jak tutaj (w niektórych pseudokodach Pascala):
function foo() : someType
begin
if( test1 == true )
then
return x;
end
doSomethignElseThatShouldnHappenIfTest1IsTrue();
return somethingElse();
end;
Cel jest jasny, a algorytm jest wystarczająco mały i na tyle nieskomplikowany, że nie gwarantuje stworzenia zmiennej „flagowej”, która przechowuje ewentualną wartość zwrotną używaną w jednym punkcie zwrotnym. Algorytm może być błędny, ale jego struktura jest na tyle prosta, że wysiłek w wykryciu błędu jest (najprawdopodobniej) znikomy.
Czasami tak nie jest (tutaj przy użyciu pseudokodu C):
switch(someVal)
{
case v1 : return x1;
case v2 : return x2:
case v3 : doSomething(); // fall-through
case v4: // fall-through
case v5: // fall-through
case v6: return someXthingie;
...
...
default:
doSomething(); // no return statement yet
}
W tym przypadku algorytm nie ma prostej struktury, a instrukcja switch (w stylu C) pozwala na kroki przejściowe, które mogą, ale nie muszą być celowo wykonywane jako część algorytmu.
Być może algorytm jest poprawny, ale źle napisany.
A może przez siły zewnętrzne przekraczające możliwości programisty jest to rzeczywista (i poprawna) reprezentacja prawnie potrzebnego algorytmu.
Może to źle
Odkrywanie prawdy w tym wszystkim wymaga znacznie więcej wysiłku niż w poprzednim przykładzie. I tu leży coś, w co mocno wierzę (pamiętajcie, że nie mam formalnych badań, które mogłyby to poprzeć):
Zakładając poprawny fragment kodu:
Wiele instrukcji return zwiększa czytelność i prostotę takiego fragmentu kodu, jeśli fragment ten reprezentuje prosty algorytm o z natury prostej strukturze przepływu. Mówiąc prościej, nie mam na myśli małych, ale rozumiem z natury zrozumiałe lub samo-dowody , które nie wymagają nieproporcjonalnego wysiłku w czytaniu (ani nie nakłaniają ludzi do wymiotowania, przeklinania czyjejś matki lub połykania kuli, gdy muszą ją przeczytać. )
Pojedyncza instrukcja return zwiększa czytelność i prostotę takiego fragmentu kodu, jeśli wartość zwracana jest albo obliczana podczas wykonywania algorytmu, albo jeśli kroki w algorytmie odpowiedzialnym za obliczenie można zgrupować w jednym miejscu w strukturze algorytmu .
Pojedyncza instrukcja return zmniejsza czytelność i prostotę takiego fragmentu kodu, jeśli wymaga przypisania do jednej lub więcej zmiennych flag, przy czym lokalizacje takich przypisań nie są jednolicie rozmieszczone w całym algorytmie.
Wiele instrukcji return zmniejsza czytelność i prostotę takiego fragmentu kodu, jeśli instrukcje return nie są równomiernie rozmieszczone w algorytmie i jeśli wyznaczają wzajemnie wykluczające się bloki kodu, które nie są jednorodne pod względem wielkości lub struktury między sobą.
Jest to ściśle związane ze złożonością fragmentu kodu, o którym mowa. A to z kolei wiąże się z miarami złożoności cyklicznej i halsteadowej. Na tej podstawie można zaobserwować:
Im większy rozmiar podprogramu lub funkcji, tym większa i bardziej złożona jest jej struktura przepływu kontroli wewnętrznej, a tym większe prawdopodobieństwo, że staniesz przed pytaniem, czy użyć instrukcji wielokrotnego, czy pojedynczego zwrotu.
Wniosek z tego jest następujący: utrzymuj małe funkcje, robiąc jedną rzecz i tylko jedną rzecz (i robiąc to dobrze). Jeśli wykażą nominalnie małe wskaźniki złożoności cyklicznej i półstrzałowej, to nie tylko będą prawdopodobnie najprawdopodobniej poprawne i będą realizacją zrozumiałych zadań, ich wewnętrzne struktury również będą stosunkowo oczywiste.
Wtedy, i tylko wtedy możesz dość łatwo i nie tracąc dużo snu, możesz zdecydować, czy użyć pojedynczego zwrotu i wielu zwrotów bez większego ryzyka wprowadzenia błędów przy którymkolwiek z tych wyborów.
Można również spojrzeć na to wszystko i zasugerować, że gdy ludzie zmagają się z problemem pojedynczych zwrotów lub wielokrotnych zwrotów, dzieje się tak dlatego, że - albo z powodu braku doświadczenia, głupoty, albo braku etyki pracy - nie piszą czystego kodu i mają tendencję do pisania potworne funkcje z całkowitym lekceważeniem miar cyklicznych i halsztowych.