Wychodząc z Pythona, gdzie zawsze istnieje „właściwy sposób” („Pythonic”), jeśli chodzi o styl, zastanawiam się, czy to samo istnieje dla Rubiego. Używam własnych wskazówek dotyczących stylu, ale myślę o wydaniu kodu źródłowego i chciałbym, aby był zgodny z wszelkimi niepisanymi regułami, które mogą istnieć.
Czy jawne wpisywanie return
metod w metodach to „The Ruby Way” ? Widziałem to zrobione zi bez, ale czy jest na to właściwy sposób? Czy jest może na to odpowiedni moment ? Na przykład:
def some_func(arg1, arg2, etc)
# Do some stuff...
return value # <-- Is the 'return' needed here?
end
ruby
coding-style
return-value
Sasha Chedygov
źródło
źródło
Odpowiedzi:
Stare (i „z odpowiedzią”) pytanie, ale w odpowiedzi dorzucę moje dwa centy.
TL; DR - nie musisz, ale w niektórych przypadkach może to uczynić twój kod bardziej przejrzystym.
Chociaż nieużywanie wyraźnego zwrotu może być „sposobem Rubiego”, jest to mylące dla programistów pracujących z nieznanym kodem lub niezaznajomionych z tą funkcją Rubiego.
To nieco wymyślony przykład, ale wyobraź sobie taką małą funkcję, która dodaje jeden do przekazanej liczby i przypisuje ją do zmiennej instancji.
Czy miała to być funkcja zwracająca wartość, czy nie? Naprawdę trudno powiedzieć, co miał na myśli programista, ponieważ zarówno przypisuje zmienną instancji, jak i zwraca również przypisaną wartość.
Załóżmy, że dużo później, inny programista (być może nie tak dobrze zaznajomiony z tym, jak Ruby zwraca na podstawie ostatniej linii wykonanego kodu) pojawia się i chce umieścić kilka instrukcji print do logowania, a funkcja staje się następująca ...
Teraz funkcja jest zepsuta, jeśli cokolwiek oczekuje zwróconej wartości . Jeśli nic nie oczekuje zwróconej wartości, wszystko jest w porządku. Oczywiście, jeśli gdzieś dalej w łańcuchu kodu coś wywołującego to oczekuje zwróconej wartości, zakończy się niepowodzeniem, ponieważ nie odzyska tego, czego oczekuje.
Prawdziwe pytanie brzmi teraz: czy coś naprawdę spodziewało się zwróconej wartości? Czy to coś zepsuło, czy nie? Czy to coś zepsuje w przyszłości? Kto wie! Dowiesz się tylko o pełnym przeglądzie kodu wszystkich połączeń.
Tak więc przynajmniej dla mnie najlepszym podejściem jest albo bardzo wyraźne, że zwracasz coś, jeśli ma to znaczenie, albo w ogóle nic nie zwracasz, gdy tak nie jest.
Więc w przypadku naszej małej funkcji demo, zakładając, że chcemy, aby zwracała wartość, byłoby to zapisane w ten sposób ...
Dla każdego programisty byłoby bardzo jasne, że zwraca wartość, a znacznie trudniej byłoby mu ją złamać, nie zdając sobie z tego sprawy.
Alternatywnie można napisać to w ten sposób i pominąć instrukcję return ...
Ale po co zawracać sobie głowę pomijaniem słowa zwrot? Dlaczego nie po prostu go tam umieścić i wyjaśnić w 100%, co się dzieje? Dosłownie nie będzie to miało wpływu na zdolność twojego kodu do działania.
źródło
return
dodaje znaczenie semantyczne do kodu, dlaczego nie? Nie jest to zbyt rozwlekłe - nie mówimy o 5 wierszach na 3, tylko jedno słowo więcej. Wolałbym widziećreturn
przynajmniej w funkcjach (może nie w blokach), aby wyrazić, co faktycznie robi kod. Czasami musisz zwrócić funkcję mid-function - nie pomijaj ostatniegoreturn
słowa kluczowego w ostatniej linii tylko dlatego, że możesz. W ogóle nie preferuję gadatliwości, ale wolę spójność.side_effect()
Inny programista zdecyduje się (ab) użyć niejawnej wartości zwracanej przez twoją procedurę. Aby to naprawić, możesz jawnie określić swoje proceduryreturn nil
.Nie. Dobry styl Ruby generalnie używa jawnych zwrotów tylko do wczesnego powrotu . Ruby specjalizuje się w minimalizmie kodu / ukrytej magii.
To powiedziawszy, jeśli wyraźny zwrot sprawiłby, że rzeczy byłyby jaśniejsze lub łatwiejsze do odczytania, nic nie zaszkodzi.
źródło
return
ma już znaczące znaczenie semantyczne jako WCZESNE WYJŚCIE z funkcji.return
w ostatniej linii jako WCZESNE WYJŚCIE?Osobiście używam
return
słowa kluczowego do rozróżnienia między tym, co nazywam metodami funkcjonalnymi , tj. Metodami, które są wykonywane głównie dla ich wartości zwracanej, od metod proceduralnych, które są wykonywane głównie ze względu na ich skutki uboczne. Tak więc metody, w których zwracana wartość jest ważna, otrzymują dodatkowereturn
słowo kluczowe, aby zwrócić uwagę na wartość zwracaną.Używam tego samego rozróżnienia przy wywoływaniu metod: metody funkcjonalne mają nawiasy, a metody proceduralne nie.
I wreszcie, używam tego rozróżnienia również w przypadku bloków: bloki funkcyjne otrzymują nawiasy klamrowe, bloki proceduralne (tj. Bloki, które coś „robią”) otrzymują
do
/end
.Jednak staram się nie podchodzić do tego religijnie: z blokami, nawiasami klamrowymi i
do
/end
mają inny priorytet, i zamiast dodawać wyraźne nawiasy, aby ujednoznacznić wyrażenie, po prostu przełączam się na inny styl. To samo dotyczy wywoływania metod: jeśli dodanie nawiasów wokół listy parametrów sprawia, że kod jest bardziej czytelny, robię to, nawet jeśli dana metoda ma charakter proceduralny.źródło
Właściwie ważne jest rozróżnienie między:
Ruby nie ma natywnego sposobu ich rozróżniania - co czyni cię podatnym na napisanie procedury
side_effect()
i innego programistę decydującego się na nadużycie niejawnej wartości zwracanej przez twoją procedurę (w zasadzie traktując ją jako nieczystą funkcję).Aby rozwiązać ten problem, wyjmij kartkę z książki Scali i Haskella i poproś o jawne zwrócenie procedur
nil
(akaUnit
lub()
w innych językach).Jeśli będziesz postępować zgodnie z tym, używanie jawnej
return
składni lub nie będzie po prostu kwestią osobistego stylu.Aby dalej rozróżnić funkcje i procedury:
do/end
()
, podczas gdy wywołując funkcje, nieZwróć uwagę, że Jörg W Mittag faktycznie zalecał odwrotną stronę - unikanie
()
s dla procedur - ale to nie jest zalecane, ponieważ chcesz, aby wywołania metod wywołujących efekt uboczny były wyraźnie odróżnialne od zmiennych, szczególnie gdy arity wynosi 0. Zobacz przewodnik stylu Scala dotyczący wywoływania metod dla Detale.źródło
function_a
ifunction_a
została napisana, aby wywołać (i może działać tylko przez wywołanie)procedure_b
, to czyfunction_a
naprawdę jest funkcją? Zwraca wartość, spełniając wymagania dotyczące funkcji, ale ma efekt uboczny, spełniając wymagania procedur.function_a
może zawierać drzewoprocedure_...
wezwań, tak jak rzeczywiścieprocedure_a
mogłoby zawierać drzewofunction_...
wezwań. Podobnie jak Scala, ale w przeciwieństwie do Haskella, w Rubim nie ma gwarancji, że funkcja nie wywołuje skutków ubocznych.Przewodnik po stylach stwierdza, że nie powinieneś używać
return
w swoim ostatnim oświadczeniu. Nadal możesz go używać, jeśli nie jest ostatni . Jest to jedna z konwencji, których społeczność ściśle przestrzega, i Ty też powinieneś, jeśli planujesz współpracować z kimkolwiek używającym Rubiego.Biorąc to pod uwagę, głównym argumentem przemawiającym za używaniem jawnego
return
s jest to, że jest to mylące dla osób pochodzących z innych języków.Typowa heurystyka długości metod (z wyłączeniem metod pobierających / ustawiających) w java to jeden ekran . W takim przypadku możesz nie widzieć definicji metody i / lub już zapomniałeś o tym, skąd wracałeś.
Z drugiej strony w Rubim najlepiej trzymać się metod krótszych niż 10 linii . Biorąc to pod uwagę, można by się zastanawiać, dlaczego musi pisać ~ 10% więcej stwierdzeń, skoro są one wyraźnie zasugerowane.
Ponieważ Ruby nie ma metod void i wszystko jest o wiele bardziej zwięzłe, po prostu dodajesz narzut bez żadnych korzyści, jeśli wybierzesz jawne
return
s.źródło
Zgadzam się z Benem Hughesem i nie zgadzam się z Timem Holtem, ponieważ pytanie dotyczy definitywnego sposobu, w jaki Python to robi i pyta, czy Ruby ma podobny standard.
To robi.
Jest to tak dobrze znana cecha języka, że każdy, kto spodziewa się debugowania problemu w Ruby, powinien o tym wiedzieć.
źródło
return
słowa kluczowego, gdy jest niepotrzebne, jest zdecydowanie złym stylem, wybranym przez społeczność .To kwestia preferowanego stylu. Musisz użyć słowa kluczowego return, jeśli chcesz powrócić gdzieś w środku metody.
źródło
Jak powiedział Ben. Fakt, że „wartość zwracana przez metodę ruby jest wartością zwracaną przez ostatnią instrukcję w treści funkcji” powoduje, że słowo kluczowe return jest rzadko używane w większości metod języka ruby.
źródło
if failed_check then nil else @list end
? To jest naprawdę funkcjonalne .