Pelo que li: O motivo é que não é fácil determinar qual método será chamado de fato, pois temos herança.
No entanto, por que o Java pelo menos não possui otimização de recursão de cauda para métodos estáticos e aplica a maneira correta de chamar métodos estáticos com o compilador?
Por que o Java não tem nenhum suporte para recursão de cauda?
Não tenho certeza se há alguma dificuldade aqui.
Em relação à duplicata sugerida , conforme explicado por Jörg W Mittag 1 :
- A outra pergunta é sobre o TCO, essa sobre o TRE. O TRE é muito mais simples que o TCO.
- Além disso, a outra pergunta pergunta sobre quais limitações a JVM impõe às implementações de linguagem que desejam compilar com a JVM, esta pergunta sobre Java, que é a única linguagem que não é restrita pela JVM, pois a especificação da JVM pode ser alterada por as mesmas pessoas que projetam Java.
- E, finalmente, não há sequer uma restrição na JVM sobre o TRE, porque a JVM possui GOTO intra-método, que é tudo o que é necessário para o TRE
1 Formatação adicionada para destacar pontos feitos.
Respostas:
Conforme explicado por Brian Goetz (arquiteto de linguagem Java da Oracle) neste vídeo :
Qualquer coisa que alterasse o número de quadros na pilha quebraria isso e causaria um erro. Ele admite que esse foi um motivo estúpido e, portanto, os desenvolvedores do JDK substituíram esse mecanismo.
Ele ainda menciona que não é uma prioridade, mas que a recursão da cauda
Nota: isso se aplica ao HotSpot e ao OpenJDK, outras VMs podem variar.
fonte
Java não possui otimização de chamada final pelo mesmo motivo que a maioria das linguagens imperativas não possui. Loops imperativos são o estilo preferido da linguagem, e o programador pode substituir a recursão da cauda por loops imperativos. A complexidade não vale a pena para um recurso cujo uso é desencorajado por uma questão de estilo.
Essa coisa em que os programadores às vezes querem escrever no estilo FP em linguagens imperativas só entrou em voga nos últimos 10 anos ou mais, depois que os computadores começaram a escalar núcleos em vez de GHz. Mesmo agora, não é tão popular. Se eu sugerisse substituir um loop imperativo pela recursão da cauda no trabalho, metade dos revisores de código riria e a outra metade pareceria confusa. Mesmo na programação funcional, você geralmente evita a recursão da cauda, a menos que outras construções, como funções de ordem superior, não se encaixem corretamente.
fonte
for
loop" (e da mesma forma para funções de primeira classe versus objetos). Eu não chegaria ao ponto de chamá-lo de "fanatismo imperativo", mas não acho que teria sido uma demanda muito alta em 1995, quando a principal preocupação provavelmente era a velocidade do Java e a falta de genéricos.Java não possui otimização de chamada alta porque a JVM não possui um bytecode para chamadas finais (para algum ponteiro de função estaticamente desconhecido , por exemplo, um método em alguma tabela).
Parece que, por razões sociais (e talvez técnicas), a adição de uma nova operação de bytecode na JVM (que a tornaria incompatível com versões anteriores dessa JVM) é terrivelmente difícil para o proprietário da especificação da JVM.
Os motivos técnicos para não incluir um novo bytecode na especificação da JVM incluem o fato de que as implementações da JVM da vida real são peças de software terrivelmente complexas (por exemplo, devido às muitas otimizações de JIT que está sendo executada).
As chamadas finais para alguma função desconhecida requerem a substituição do quadro de pilha atual por um novo, e essa operação deve ficar na JVM (não é apenas uma questão de alterar o compilador gerador de bytecode).
fonte
A menos que um idioma tenha uma sintaxe especial para fazer uma chamada final (recursiva ou não) e um compilador gritar quando uma chamada final for solicitada, mas não puder ser gerada, a otimização "opcional" da chamada final ou da recursão final produzirá situações em que uma peça do código pode exigir menos de 100 bytes de pilha em uma máquina, mas mais de 100.000.000 bytes de pilha em outra. Tal diferente deve ser considerado qualitativo, e não meramente quantitativo.
Espera-se que as máquinas tenham tamanhos de pilha diferentes e, portanto, é sempre possível que o código funcione em uma máquina, mas exploda a pilha em outra. Geralmente, no entanto, o código que funcionará em uma máquina mesmo quando a pilha é artificialmente restrita provavelmente funcionará em todas as máquinas com tamanhos de pilha "normais". Se, no entanto, um método que percorre 1.000.000 de profundidade for otimizado para uma chamada final em uma máquina, mas não em outra, a execução na máquina anterior provavelmente funcionará mesmo que sua pilha seja incomumente pequena e falhe na segunda, mesmo que sua pilha seja extraordinariamente grande .
fonte
Eu acho que a recursão da chamada de cauda não é usada em Java principalmente porque isso alteraria os rastreamentos de pilha e, portanto, tornaria a depuração de um programa muito mais difícil. Acho que um dos principais objetivos do Java é permitir que os programadores depurem facilmente seu código, e o rastreamento de pilha é essencial para fazer isso, especialmente em um ambiente de programação altamente orientado a objetos. Como a iteração poderia ser usada, o comitê de idiomas deve ter percebido que não vale a pena adicionar recursão final.
fonte