Zamiast wspierać przeciążanie metod, Ruby nadpisuje istniejące metody. Czy ktoś może wyjaśnić, dlaczego język został zaprojektowany w ten sposób?
146
Przeciążenie metod można osiągnąć, deklarując dwie metody o tej samej nazwie i różnych podpisach. Te różne podpisy mogą być:
method(int a, int b) vs method(String a, String b)
method(a) vs method(a, b)
Nie możemy osiągnąć przeciążenia metod przy użyciu pierwszego sposobu, ponieważ nie ma deklaracji typu danych w ruby ( dynamiczny język typizowany ). Zatem jedynym sposobem zdefiniowania powyższej metody jestdef(a,b)
W przypadku drugiej opcji może się wydawać, że możemy osiągnąć przeciążenie metody, ale nie możemy. Powiedzmy, że mam dwie metody z różną liczbą argumentów,
def method(a); end;
def method(a, b = true); end; # second argument has a default value
method(10)
# Now the method call can match the first one as well as the second one,
# so here is the problem.
Tak więc ruby musi zachować jedną metodę w łańcuchu wyszukiwania metod o unikalnej nazwie.
„Przeciążanie” to termin, który po prostu nie ma sensu w Rubim. To jest w zasadzie synonimem „statycznego wysłania argumentu opartego na”, ale Ruby nie posiada statyczną wysyłkę w ogóle . Zatem powodem, dla którego Ruby nie obsługuje wysyłania statycznego na podstawie argumentów, jest to, że nie obsługuje on wysyłania statycznego, kropka. Nie obsługuje wysyłania statycznego żadnego rodzaju , opartego na argumentach lub w inny sposób.
Teraz, jeśli tak naprawdę nie pytasz konkretnie o przeciążanie, ale może o dynamiczne wysyłanie oparte na argumentach, odpowiedź brzmi: ponieważ Matz tego nie zaimplementował. Ponieważ nikt inny nie zadał sobie trudu, aby to zaproponować. Ponieważ nikt inny nie zadał sobie trudu, aby go wdrożyć.
Ogólnie rzecz biorąc, dynamiczne rozsyłanie oparte na argumentach w języku z opcjonalnymi argumentami i listami argumentów o zmiennej długości jest bardzo trudne do wykonania, a jeszcze trudniej jest zachować zrozumiałość. Nawet w językach ze statycznym wysyłaniem opartym na argumentach i bez argumentów opcjonalnych (jak na przykład Java), czasami dla zwykłego śmiertelnika prawie niemożliwe jest określenie, które przeciążenie zostanie wybrane.
W C # można faktycznie zakodować dowolny problem 3-SAT w celu rozwiązania przeciążenia, co oznacza, że rozwiązanie przeciążenia w C # jest NP-trudne.
Teraz spróbuj tego z dynamiczną wysyłką, gdzie masz dodatkowy wymiar czasu, który musisz zachować w swojej głowie.
Istnieją języki, które są wysyłane dynamicznie na podstawie wszystkich argumentów procedury, w przeciwieństwie do języków zorientowanych obiektowo, które wysyłają tylko na podstawie „ukrytego”
self
argumentu zerowego . Na przykład Common Lisp rozsyła typy dynamiczne, a nawet wartości dynamiczne wszystkich argumentów. Clojure wysyła dowolną funkcję wszystkich argumentów (co przy okazji jest niezwykle fajne i niezwykle potężne).Ale nie znam żadnego języka OO z dynamiczną dystrybucją opartą na argumentach. Martin Odersky powiedział, że mógłby rozważyć dodanie wysyłania opartego na argumentach do Scali, ale tylko wtedy, gdy może jednocześnie usunąć przeciążenie i być wstecznie kompatybilnym zarówno z istniejącym kodem Scala, który używa przeciążenia, jak i kompatybilnym z Javą (szczególnie wspomniał o Swing i AWT które odgrywają niezwykle złożone sztuczki, ćwicząc prawie każdy paskudny ciemny kąt raczej skomplikowanych reguł przeciążania Javy). Sam miałem kilka pomysłów na dodanie wysyłania opartego na argumentach do Rubiego, ale nigdy nie mogłem wymyślić, jak to zrobić w sposób zgodny wstecz.
źródło
def method(a, b = true)
nie zadziała, dlatego przeciążanie metod jest niemożliwe”. To nie jest; to jest po prostu trudne. Uważam jednak, że TA odpowiedź jest naprawdę pouczająca.Zakładam, że szukasz możliwości zrobienia tego:
Ruby obsługuje to w inny sposób:
Typowym wzorcem jest również przekazywanie opcji jako hash:
Mam nadzieję, że to pomoże
źródło
Przeciążanie metod ma sens w języku z typowaniem statycznym, w którym można rozróżnić różne typy argumentów
a także między różnymi liczbami argumentów
Pierwsze rozróżnienie nie istnieje w rubinie. Ruby używa dynamicznego pisania lub "kaczego pisania". Drugie rozróżnienie można obsłużyć domyślnymi argumentami lub pracując z argumentami:
źródło
To nie odpowiada na pytanie, dlaczego Ruby nie ma przeciążania metod, ale biblioteki innych firm mogą to zapewnić.
Contracts.ruby biblioteka umożliwia przeciążanie. Przykład zaczerpnięty z samouczka:
Zauważ, że jest to w rzeczywistości potężniejsze niż przeciążanie Javy, ponieważ możesz określić wartości do dopasowania (np.
1
), A nie tylko typy.Zauważysz jednak zmniejszoną wydajność przy użyciu tego; będziesz musiał przeprowadzić testy porównawcze, aby zdecydować, ile możesz tolerować.
źródło
Często wykonuję następującą strukturę:
Pozwala to użytkownikowi obiektu na użycie czystej i przejrzystej metody nazwa_metody: metoda Jeśli jednak chce zoptymalizować wykonanie, może bezpośrednio wywołać właściwą metodę.
Ponadto sprawia, że test jest bardziej przejrzysty i lepszy.
źródło
są już świetne odpowiedzi na pytanie dlaczego. Jeśli jednak ktoś szuka innych rozwiązań, sprawdź funkcjonalno-rubinową perełkę zainspirowaną dopasowaniem wzorów Elixir .
źródło