La JVM impedisce le ottimizzazioni delle chiamate di coda?


99

Ho visto questa citazione sulla domanda: cos'è un buon linguaggio funzionale su cui costruire un servizio web?

Scala, in particolare, non supporta l'eliminazione delle chiamate di coda tranne che nelle funzioni auto-ricorsive, che limita i tipi di composizione che puoi fare (questa è una limitazione fondamentale della JVM).

È vero? In caso affermativo, di cosa si tratta la JVM che crea questa limitazione fondamentale?

Risposte:


74

Questo post: Ricorsione o iterazione? potrebbe aiutare.

In breve, l'ottimizzazione della chiamata di coda è difficile da eseguire nella JVM a causa del modello di sicurezza e della necessità di avere sempre a disposizione una traccia dello stack. Questi requisiti potrebbero in teoria essere supportati, ma probabilmente richiederebbe un nuovo bytecode (vedere la proposta informale di John Rose ).

Ci sono anche altre discussioni in Sun bug # 4726340 , dove termina la valutazione (dal 2002):

Credo che ciò possa essere fatto comunque, ma non è un compito da poco.

Attualmente, c'è del lavoro in corso nel progetto Da Vinci Machine . Lo stato del sottoprogetto della chiamata di coda è elencato come "proto 80%"; è improbabile che entri in Java 7, ma penso che abbia ottime possibilità con Java 8.


Non ho seguito completamente la spiegazione. Pensavo che l'ottimizzazione della chiamata di coda fosse implementata dal compilatore. Supponendo che tu abbia una funzione che potrebbe essere ottimizzata per la chiamata di coda dal compilatore, potresti anche avere una funzione non ricorsiva equivalente che implementa la stessa funzionalità usando un ciclo, giusto? Se è così, non potrebbe essere fatto dal compilatore. Non sono in grado di seguire la dipendenza dalla JVM. Come si confronta con un compilatore Scheme che ha generato codice i386 nativo?
Gautham Ganapathy

4
@Gautham: la mia dichiarazione sul debug era in riferimento all'uso dei trampolini come soluzione alternativa per la mancanza di eliminazione delle chiamate di coda sulla JVM. L'eliminazione della chiamata di coda può ed è stata implementata sulla JVM (Arnold Schaighofer lo ha fatto in OpenJDK e anche LLVM), quindi non c'è dubbio se possa essere eseguita o meno. Il CLR di Microsoft, ovviamente, supporta l'eliminazione delle tail call da 10 anni e il rilascio di F # ha dimostrato che è un punto di svolta. Penso che la risposta sia che la JVM è rimasta ferma da tempo.
JD

3
Questo è un malinteso comune e una scusa ripetuta, ma non è corretto. È ormai consolidato da diversi anni che la sicurezza mediante l'ispezione dello stack (e la fornitura di utili stack trace) non è incompatibile con le chiamate di coda appropriate. Ad esempio, vedere questo documento del 2004. citeseerx.ist.psu.edu/viewdoc/… Downvoting, poiché la risposta non è corretta.
Justin Sheehy,

5
@JustinSheehy: cosa non è corretto? La domanda era: "La JVM impedisce le ottimizzazioni delle chiamate di coda?" E la risposta è: "No, ma è difficile".
Michael Myers

5
sai se in java8 è incluso?
nachokk

27

La limitazione fondamentale è semplicemente che la JVM non fornisce chiamate di coda nel suo codice byte e, di conseguenza, non esiste un modo diretto per un linguaggio costruito sulla JVM di fornire le chiamate di coda stessa. Ci sono soluzioni alternative che possono ottenere un effetto simile (ad esempio trampolino elastico) ma hanno il grave costo di prestazioni terribili e offuscamento del codice intermedio generato che rende inutile un debugger.

Pertanto, la JVM non può supportare alcun linguaggio di programmazione funzionale di qualità di produzione fino a quando Sun non implementa le chiamate di coda nella stessa JVM. Ne discutono da anni, ma dubito che implementeranno mai le tail call: sarà molto difficile perché hanno ottimizzato prematuramente la loro VM prima di implementare tali funzionalità di base, e l'impegno di Sun è fortemente focalizzato sui linguaggi dinamici piuttosto che sui linguaggi funzionali.

Quindi c'è un argomento molto forte che Scala non è un vero linguaggio di programmazione funzionale: questi linguaggi hanno considerato le chiamate di coda come una caratteristica essenziale da quando Scheme è stato introdotto per la prima volta oltre 30 anni fa.


5
Hence there is a very strong argument that Scala is not a real functional programming language - l'argomento è in realtà piuttosto debole. Certo tail calls [as] an essential feature, e bello se l'hardware sottostante (o la macchina virtuale) lo supporta direttamente. Ma sono dettagli di implementazione.
Ingo

8
@Ingo: solo se non si considerano gli stack overflow nel programma in fase di esecuzione visti dall'utente come un problema significativo. Secondo il suo bug tracker, anche lo stesso compilatore Scala è stato afflitto da overflow dello stack. Quindi anche gli sviluppatori Scala più esperti continuano a sbagliare ...
JD

7
Va bene essere un sostenitore di, ad esempio F #. Ma ti ho notato da molto tempo (anche anni prima in Usenet) per essere ostile a tutto ciò che non è F #, eppure le tue elaborazioni mostrano che non sai di cosa stai parlando. Come qui: il tuo argomento sembra essere che un linguaggio in cui posso scrivere un programma che si interrompe con lo stack overflow non è funzionale? Ma non si potrebbe fare lo stesso argomento per le lingue in cui posso provocare l'overflow dell'heap? Quindi, il sacro F # stesso non sarebbe considerato funzionale.
Ingo

7
@Ingo: Diversi idiomi nella programmazione funzionale, come la ricorsione reciproca e lo stile di passaggio di continuazione, possono richiedere l'eliminazione delle chiamate di coda per funzionare. Senza di esso, i tuoi programmi andranno in overflow. Se una lingua non può eseguire in modo affidabile un codice funzionale idiomatico, è funzionale? La risposta è un giudizio, come dici tu, ma una distinzione importante nella pratica. Martin Trojer ha appena pubblicato un interessante post sul blog su questo argomento
JD

2
tuttavia, solo perché la JVM (purtroppo, non c'è dubbio) non può fare chiamate di coda, ciò non significa che l'eliminazione delle chiamate di coda sia impossibile. È come se si affermasse che i calcoli in virgola mobile sono possibili solo su computer con FPU.
Ingo

22

Scala 2.7.x supporta l'ottimizzazione della chiamata di coda per l'auto-ricorsione (una funzione che chiama se stessa) dei metodi finali e delle funzioni locali.

Scala 2.8 potrebbe anche avere il supporto della libreria per il trampolino, che è una tecnica per ottimizzare le funzioni reciprocamente ricorsive.

Molte informazioni sullo stato della ricorsione in Scala possono essere trovate nel blog di Rich Dougherty .


Potete, per favore, aggiornare la domanda sullo stato corrente della scala?
om-nom-nom

@ om-nom-nom AFAIK, nulla è cambiato, né dal lato Scala, né dal lato JVM.
Daniel C. Sobral


0

Tutte le fonti indicano che la JVM non è in grado di ottimizzare nel caso della ricorsione in coda, ma dopo aver letto l' ottimizzazione delle prestazioni di Java (2003, O'reilly) ho scoperto che l'autore afferma di poter ottenere prestazioni di ricorsione maggiori implementando la ricorsione in coda.

Puoi trovare la sua affermazione a pagina 212 (cerca 'ricorsione della coda' dovrebbe essere il secondo risultato). Cosa succede?


IBM ha supportato una qualche forma di TCO nella propria implementazione JVM (come ottimizzazione, quindi nessuna garanzia). Forse gli autori dell'ottimizzazione delle prestazioni di Java pensavano che questa funzionalità sarebbe stata implementata da tutte le JVM. ibm.com/developerworks/java/library/j-diag8.html
llemieng
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.