2012-05-16 1 views
13

Я вижу два способа реализации привязок let. Во-первых, как известно из SICP, let может быть реализовано как лямбда-функция. Это удобно и просто, но с учетом того факта, что каждый лямбда (fn) переведен в отдельный класс в JVM, и количество раз let используется в средней программе, это кажется очень и очень дорогостоящим.Как `let` внедряется в Clojure и каковы его накладные расходы?

Второе, let привязки могут быть переведены непосредственно в локальные переменные Java. Это дает очень небольшие накладные расходы, но сохранение привязок в стеке нарушает семантику языка: в этом случае создание закрытий просто невозможно - сохраненные значения будут уничтожены сразу после разворачивания стека.

Итак, какова фактическая реализация, используемая в Clojure? Оценивается ссылка на соответствующие строки в источнике Clojure.

ответ

16

let Исходящие переменные хранятся как final Локальные значения в стеке.

Поскольку они являются окончательными, при необходимости они могут быть привязаны к закрытию (это аналогично тому, как вы можете использовать конечную локальную переменную в анонимном внутреннем классе в Java). Под капотом JVM копирует значение в объект, представляющий замыкание (где он хранится как окончательное поле). В результате закрытие по-прежнему работает даже после того, как рама стека уходит.

В целом, ограниченные переменные являются чрезвычайно низкими накладными расходами, вы не должны колебаться вообще от их использования с точки зрения производительности. Вероятно, на JVM не может быть лучше.

+0

Итак, я понимаю, что объект закрытия создан (и конечные переменные копируются на него) только тогда, когда это необходимо, и для простых случаев vars остаются в стеке? – ffriend

+0

Да, это в значительной степени, как это работает. Если вас это интересует, вы можете зарыться в: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java (хотя не совсем понятно выяснить, что такое Clojure's компилятор делает, есть много «магии») – mikera

+0

@ffriend Java имеет переменные с областью действия (в отличие от области метода). Я не смотрел, что делает компилятор Clojure, но кажется, что * let * может быть просто реализован блоком кода, содержащим конечные переменные. Я не уверен, почему вы думаете, что это будет реализовано с закрытием. –

1

Локальные переменные - это указатели, выделенные в стеке, указывающие на значения/объекты в куче. Указатель выходит из области видимости, но объект остается в живых до тех пор, пока закрытие сохраняет указатель на него.

 Смежные вопросы

  • Нет связанных вопросов^_^