2012-05-16 9 views
13

Sono in grado di vedere 2 modi per implementare i collegamenti let. Innanzitutto, come noto da SICP, let può essere implementato come funzione lambda. Questo è comodo e semplice, ma tenendo conto del fatto che ogni lambda (fn) viene tradotto in una classe separata in JVM e il numero di volte in cui viene utilizzato lo let nel programma medio, sembra molto, molto costoso.Come viene implementato `let` in Clojure e qual è il suo overhead?

Secondo, let associazioni possono essere convertite direttamente in variabili locali Java. Questo dà un sovraccarico molto piccolo, ma la memorizzazione dei binding su una pila infrange la semantica del linguaggio: in questo caso la creazione di chiusure è semplicemente impossibile - i valori salvati verranno distrutti subito dopo lo srotolamento dello stack.

Quindi, qual è l'implementazione effettiva utilizzata in Clojure? È apprezzato puntare a linee corrispondenti nella sorgente Clojure.

risposta

16

let variabili -bound sono memorizzate come finale valori locali nello stack.

Poiché sono definitivi, possono essere associati a chiusure se necessario (questo è analogo a come è possibile utilizzare una variabile locale finale in una classe interna anonima in Java). Sotto il cofano, la JVM copia il valore nell'oggetto che rappresenta la chiusura (dove è memorizzato come campo finale). Di conseguenza, la chiusura funziona ancora anche dopo che la cornice dello stack è scomparsa.

In generale, le variabili let-bound sono estremamente basse, non dovresti avere alcuna esitazione dall'usarle dal punto di vista delle prestazioni. Probabilmente non è possibile fare di meglio sulla JVM.

+0

Quindi ho capito che l'oggetto di chiusura viene creato (e le variabili finali vengono copiate su di esso) solo quando necessario e per i casi in cui le vars rimangono solo nello stack? – ffriend

+0

sì, è praticamente come funziona. Se sei interessato, puoi fare uno scavo in: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java (anche se non è particolarmente facile capire cosa sia Clojure il compilatore sta facendo, c'è un sacco di "magia") – mikera

+0

@ffriend Java ha variabili con scope a blocchi (al contrario dell'ambito del metodo). Non ho visto cosa fa il compilatore Clojure ma sembra che * let * possa essere semplicemente implementato da un blocco di codice contenente variabili finali. Non sono sicuro del motivo per cui pensi che sarebbe stato implementato con una chiusura. –

1

Le variabili locali sono puntatori, allocati nello stack, che puntano a valori/oggetti sull'heap. Il puntatore esce dall'ambito, ma l'oggetto rimane attivo fino a quando la chiusura mantiene un puntatore.

Problemi correlati