Z tego, co przeczytałem: Powodem jest to, że nie jest łatwo ustalić, która metoda zostanie faktycznie wywołana, ponieważ mamy dziedziczenie.
Dlaczego jednak Java nie ma przynajmniej optymalizacji rekurencji dla metod statycznych i nie wymusza właściwego sposobu wywoływania metod statycznych za pomocą kompilatora?
Dlaczego Java nie ma żadnego wsparcia dla rekursji ogona?
Nie jestem pewien, czy w ogóle są tu jakieś trudności.
Jeśli chodzi o sugerowany duplikat , jak wyjaśniono w Jörg W Mittag 1 :
- Drugie pytanie dotyczy TCO, w tym TRE. TRE jest znacznie prostszy niż TCO.
- Także inne pytanie dotyczy tego, jakie ograniczenia JVM nakłada na implementacje językowe, które chcą się skompilować do JVM, pytanie to dotyczy Java, która jest jedynym językiem, który nie jest ograniczony przez JVM, ponieważ specyfikację JVM można zmienić przez ci sami ludzie, którzy projektują Javę.
- I na koniec, nie ma nawet ograniczeń w JVM dotyczących TRE, ponieważ JVM ma wewnętrzną metodę GOTO, która jest wszystkim, co jest potrzebne do TRE
1 Dodano formatowanie do wywołanych punktów.
Odpowiedzi:
Jak wyjaśnił Brian Goetz (architekt języka Java w Oracle) w tym filmie :
Wszystko, co zmieniło liczbę ramek na stosie, zepsułoby to i spowodowałoby błąd. Przyznaje, że był to głupi powód, dlatego programiści JDK zastąpili ten mechanizm.
Następnie wspomina, że nie jest to priorytet, ale rekursja ogona
Uwaga: dotyczy to HotSpot i OpenJDK, inne maszyny wirtualne mogą się różnić.
źródło
Java nie ma optymalizacji wywołania ogona z tego samego powodu, dla którego większość imperatywnych języków tego nie ma. Pętle imperatywne są preferowanym stylem języka, a programista może zastąpić rekurencję ogonami pętlami imperatywnymi. Złożoność nie jest tego warta w przypadku funkcji, której użycie jest odradzane ze względu na styl.
To, w czym programiści chcą czasami pisać w stylu FP w skądinąd imperatywnych językach, stało się modne dopiero w ciągu ostatnich 10 lat, po tym jak komputery zaczęły skalować się w rdzeniach zamiast GHz. Nawet teraz nie jest tak popularny. Gdybym zasugerował zastąpienie pętli rozkazów rekurencją ogona w pracy, połowa recenzentów kodu śmiałaby się, a druga połowa wyglądałaby na zdezorientowanych. Nawet w programowaniu funkcjonalnym na ogół unika się rekurencji ogona, chyba że inne konstrukcje, takie jak funkcje wyższego rzędu, nie pasują idealnie.
źródło
for
pętli” (podobnie do pierwszej klasy funkcji vs obiektów). Nie posunąłbym się tak daleko, że nazwałbym to „imperatywną bigoterią”, ale nie sądzę, że byłby bardzo potrzebny w 1995 roku, kiedy najważniejszą kwestią była prawdopodobnie szybkość Javy i brak generycznych.Java nie ma optymalizacji wysokich wywołań, ponieważ JVM nie ma kodu bajtowego dla wywołań tail (do jakiegoś statycznie nieznanego wskaźnika funkcji, np. Metody w niektórych vtable).
Wygląda na to, że z przyczyn społecznych (i być może technicznych) dodanie nowej operacji kodu bajtowego w JVM (co spowodowałoby, że byłaby niezgodna z wcześniejszymi wersjami tej JVM) jest niezwykle trudne dla właściciela specyfikacji JVM.
Techniczne powody, dla których nie dodano nowego kodu bajtowego do specyfikacji JVM, obejmują fakt, że rzeczywiste implementacje JVM są strasznie złożonymi elementami oprogramowania (np. Z powodu wielu optymalizacji JIT).
Wywołania Tail do jakiejś nieznanej funkcji wymagają zastąpienia bieżącej ramki stosu nową, a ta operacja powinna znajdować się w JVM (nie chodzi tylko o zmianę kompilatora generującego kody bajtowe).
źródło
O ile język nie ma specjalnej składni do wykonywania wywołania ogonowego (rekurencyjnego lub w inny sposób), a kompilator będzie skrzeczał, gdy żąda się wywołania ogona, ale nie można go wygenerować, „opcjonalna” optymalizacja wywołania ogona lub rekurencji ogona da sytuacje, w których kawałek kodu może wymagać mniej niż 100 bajtów stosu na jednym komputerze, ale więcej niż 100 000 000 bajtów stosu na innym komputerze. Taką różnicę należy traktować raczej jakościowo niż ilościowo.
Oczekuje się, że maszyny mogą mieć różne rozmiary stosów, dlatego zawsze jest możliwe, aby kod działał na jednej maszynie, ale wysadzał stos na innej. Zasadniczo jednak kod, który będzie działał na jednej maszynie, nawet gdy stos jest sztucznie zawężony, prawdopodobnie będzie działał na wszystkich komputerach z „normalnymi” rozmiarami stosów. Jeśli jednak metoda, która powtarza 1 000 000 głębokości, jest zoptymalizowana na jednym komputerze, ale nie na innej, wykonanie na pierwszej maszynie prawdopodobnie zadziała, nawet jeśli jej stos jest niezwykle mały, i zawiedzie na drugiej, nawet jeśli jej stos jest niezwykle duży .
źródło
Sądzę, że rekurencja wywołania ogona nie jest używana w Javie głównie dlatego, że zmieniłoby to ślady stosu i dlatego znacznie utrudniłoby debugowanie programu. Myślę, że jednym z głównych celów Javy jest umożliwienie programistom łatwego debugowania kodu, a śledzenie stosu jest niezbędne, aby to zrobić, szczególnie w wysoce obiektowym środowisku programistycznym. Ponieważ zamiast tego można zastosować iterację, komitet językowy musiał zorientować się, że nie warto dodawać rekurencji ogona.
źródło