2012-05-16 6 views
13

Ich kann 2 Möglichkeiten der Implementierung let Bindings sehen. Erstens, wie aus SICP bekannt ist, kann let als Lambda-Funktion implementiert werden. Dies ist bequem und einfach, aber unter Berücksichtigung der Tatsache, dass jedes Lambda (fn) in JVM in separate Klasse übersetzt wird und die Anzahl let im Durchschnitt Programm verwendet wird, scheint dies sehr, sehr teuer.Wie ist `Let` in Clojure implementiert und was ist sein Overhead?

Zweitens, let Bindungen können direkt in lokale Java-Variablen übersetzt werden. Dies verursacht sehr wenig Overhead, aber das Speichern von Bindungen auf einem Stapel bricht die Sprachsemantik: In diesem Fall ist das Erstellen von Schließungen einfach unmöglich - gespeicherte Werte werden direkt nach dem Abwickeln des Stapels zerstört.

Was ist die tatsächliche Implementierung in Clojure? Auf entsprechende Zeilen in Clojure-Quelle zu zeigen, wird geschätzt.

Antwort

16

let -gebundene Variablen werden als endgültige lokale Werte auf dem Stapel gespeichert.

Da sie endgültig sind, können sie bei Bedarf in Schließungen eingebunden werden (analog dazu können Sie eine letzte lokale Variable in einer anonymen inneren Klasse in Java verwenden). Unter der Haube kopiert die JVM den Wert in das Objekt, das die Schließung darstellt (wo es als letztes Feld gespeichert wird). Dadurch funktioniert der Verschluss auch nach Wegfall des Stapelrahmens.

Insgesamt sind Let-gebundene Variablen extrem niedrig, Sie sollten nicht zögern, sie aus einer Leistungsperspektive zu verwenden. Es ist wahrscheinlich nicht möglich, die JVM besser zu machen.

+0

Also verstehe ich Verschlussobjekt erstellt wird (und endgültige Variablen kopiert werden) nur bei Bedarf und für einfache Fälle vars bleiben nur auf dem Stapel? – ffriend

+0

Ja, das ist so, wie es funktioniert. Wenn Sie interessiert sind, können Sie sich in: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java (obwohl es nicht besonders leicht ist herauszufinden, was Clojure ist) haben Compiler tut, es gibt eine Menge "Magie") – mikera

+0

@ffriend Java hat Block-Bereichsvariablen (im Gegensatz zu Methodenbereich). Ich habe nicht untersucht, was der Clojure-Compiler tut, aber es scheint, dass * let * einfach durch einen Code-Block implementiert werden kann, der die endgültigen Variablen enthält. Ich bin nicht sicher, warum Sie denken, dass es mit einer Schließung umgesetzt worden wäre. –

1

Lokale Variablen sind Zeiger, die auf dem Stack zugeordnet sind und auf Werte/Objekte auf dem Heap zeigen. Der Zeiger verlässt den Gültigkeitsbereich, aber das Objekt bleibt so lange bestehen, wie der Abschluss einen Zeiger darauf behält.

Verwandte Themen