Каковы преимущества динамического определения объема? - PullRequest
27 голосов
/ 26 ноября 2008

Я узнал, что статическая область видимости - единственный разумный способ сделать что-то, и что динамическая область видимости - инструмент дьявола, и это результат только плохой реализации интерпретаторов / составители.

Затем я увидел этот фрагмент из Common Lisp vs. Scheme статьи:

Both Lexically and Dynamically    Lexical scope only, per the standard.
scoped special vars.  Common      Dynamically scoped vars are provided
Lisp just wins on this point.     by some implementations as an extension
                                  but code using them is not portable.

     (I have heard the arguments about whether Dynamic scoping
      is or is not a Bad Idea in the first place.  I don't care. 
      I'm just noting that you can do things with it that you 
      can't easily do without it.)

Почему Common Lisp "просто побеждает в этом вопросе"? Какие вещи проще сделать с динамической областью действия? Я действительно не могу оправдать когда-либо необходимость / видя это как хорошую вещь.

Ответы [ 10 ]

34 голосов
/ 26 ноября 2008

Как и все остальное, Dynamic Scoping - всего лишь инструмент. При правильном использовании это может облегчить выполнение определенных задач. При неправильном использовании он может вызывать ошибки и головные боли.

Я, конечно, вижу некоторые варианты использования. Можно исключить необходимость передачи переменных некоторым функциям.

Например, я мог бы настроить отображение в начале программы, и каждая графическая операция просто предполагает это отображение.

Если я хочу настроить окно внутри этого дисплея, то я могу «добавить» это окно в стек переменных, который в противном случае определяет отображение, и любые графические операции, выполняемые в этом состоянии, перейдут к окну, а не к дисплей в целом.

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

-Adam

14 голосов
/ 26 ноября 2008

Основной риск с динамическим охватом - непредвиденные последствия. Динамическая область действия заставляет область видимости следовать за стеком времени выполнения, что означает, что набор символов в области видимости намного больше и далеко не очевиден с точки зрения использования любого символа. Переменные с динамической областью очень похожи на глобальные переменные, только может быть более одной версии каждой переменной с видимым только самым последним определением, скрывая все остальные.

Динамическая область, насколько она полезна, она полезна для поведения, которое должно быть чувствительным к стеку времени выполнения. Например (и вообще говоря, не относится к Лиспу или вариантам):

  • обработка исключений - самый верхний блок catch находится в области действия при возникновении исключения
  • безопасность - безопасность на основе кода .NET принимает решения о доступности определенных привилегированных API-интерфейсов на основе того, что код назвал его.

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

6 голосов
/ 03 мая 2009

Динамическая область действия позволяет определять контекстные функции. В этом смысле это очень похоже на внедрение зависимостей в современных средах. (Например, рассмотрим, когда вы аннотируете Java-класс с определениями внедрения зависимостей, чтобы обеспечить прозрачную инициализацию различных ссылок. (Ср. Spring, или JPA и т.

Очевидно, что динамическое определение объема делает определенные предположения относительно характеристик времени выполнения сайта вызова для данной функции, которые не могут быть гарантированы во время компиляции (или проектирования). Опять же, следуя примеру современного (Java) компонента инфраструктуры, если вы создаете экземпляр такого класса вне контролируемой среды (среды выполнения) контейнера, вполне возможно, что класс не сможет функционировать, учитывая его необходимые зависимости. не будет инициализирован (он же введен).

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

6 голосов
/ 26 ноября 2008

Динамическая область видимости полезна в некоторых предметно-ориентированных языках. В частности, это может быть удобно на языках таблиц стилей. Мой опыт написан на языке стилей GNU TeXmacs .

На этом языке параметры отображения хранятся в динамически изменяемых переменных. Эти переменные влияют на рендеринг каждого атома в их области, включая атомы, которые создаются функциями, вызываемыми в области.

Динамическая область видимости в TeXmacs также используется, среди прочего, для маркировки перекрестных ссылок. Якоря, используемые для перекрестных ссылок, получают свою этикетку из своего окружения. Например, якорь, включенный в блок формулы, будет использовать номер формулы в качестве метки вместо номера раздела для якоря, расположенного после формулы.

Если подумать, переменные среды unix также являются динамически переменными. Хотя внутренние области не могут изменять значение переменных во внешних областях.

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

4 голосов
/ 02 апреля 2011

Также обратите внимание, что объединение

  • концепция лексическая область действия (что, как мы считаем, является хорошей вещью для языка программирования, в отличие от динамическая область действия )
  • с определениями функций (лямбда-выражениями), глубоко внедренными в код (такие определения можно также назвать «вложенными функциями», чтобы быть короткими)

может оказаться сложным делом, как с точки зрения языковой реализации, так и с точки зрения программиста. У этой сложной вещи есть даже специальное название: closure .

Как Википедия пишет :

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

Это не только нетривиально для реализации в языке с глобальными и / или изменяемыми переменными (такими как C или Java; подумайте об обеспечении правильного доступа в момент оценки закрытия к изменяемому состоянию, которое находилось в области видимости на месте определения вложенной функции! Только одно: использованные объекты не должны были быть уничтожены и собраны мусором при оценке закрытия в будущем), но также концептуально это не тривиально для программисту подумать о том, как замыкание будет работать в сложной ситуации и какие (побочные) эффекты оно будет иметь точно (по той же причине: нужно подумать о взаимодействии замыкания со всем изменяемым состоянием, которое было в области видимости, когда вы определили замыкание, например: когда вы ссылаетесь внутри определения замыкания на внешнюю изменяемую переменную, которая находится в области действия, действительно ли вы хотите получить доступ к значению, которое переменная имела во время определения закрытие, т. е. вы хотите иметь только для чтения копию т переменная, или вы хотите полноценный доступ к изменяемому состоянию переменной в будущем во время оценки замыкания? ).

В чисто функциональных языках гораздо проще думать об определениях вложенных функций и их использовании, и поэтому наличие только лексической области видимости для них вообще не проблема. Но если ваш язык не функционален, это не так тривиально. (Я полагаю, что это одна из причин, почему долго обсуждали, как добавлять замыкания в Java: они не казались достаточно тривиальными для понимания программистом, хотя они просто основывались на хорошей концепции лексического контекста .)

Думать о вложенных функциях в не чисто функциональных языках проще с динамической областью (хотя динамическая область не очень приятна: вы получаете меньше проверок во время компиляции и гарантии правильного поведения вашей программы с динамической областью действия).

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

Примечания

Относительно длинной истории (нет) замыканий в Java (и того, что программистам не понравилась концепция) - http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg04030.html:

Дата: четверг, 14 августа 2003 г. 08:05:44 -0700

От: Майкл Ванье

Тема: Re: привязки и назначения (было: Re: продолжения)

Дата: четверг, 14 августа 2003 г. 10:45:34 -0400

От: "Дэвид Б. Такер"

Я представляю, хотя у меня нет статистических данных, что Требование объявления локальных переменных, чтобы быть окончательным, чтобы ссылаться на них внутри анонимных внутренних классов (замыканий) почти полностью неизвестен и не используется на практике.

Из любопытства кто-нибудь знает, почему Java допускает только финал? переменныессылаться из анонимных классов?

Dave

   <cynic>Otherwise you'd have the equivalent of true closures,
and if you had that    java would be a
*really* powerful and useful language, so they obviously    couldn't do that.
</cynic>

Собственно, реализация прототипа did позволял ссылаться на не финальные переменные из внутренних классов. Был протест от пользователей , жаловаться что не хотели этот! Причина была интересной: в Для того, чтобы поддерживать такие переменные, это нужно было их куча-выделить, и (в то время, по крайней мере) средний Java-программист был еще довольно капризный о распределении кучи и сборка мусора и все такое. Они не одобряли язык выполнение выделения кучи "под стол ", когда не было ни одного случая "новое" ключевое слово в поле зрения.

Итак, в первые дни - по-видимому - «третий» подход (в отличие от двух, о которых я упоминал в моем тексте выше) должен был быть принят в Java: ни «копии только для чтения», ни реальный доступ во время оценки к включающему (во время определения замыкания) изменчивому состоянию, но скорее изменчивым копиям состояния (по крайней мере, я так понимаю процитированный отрывок, или нет, он говорит о выделять кучу только ссылок? .. Тогда это второй вариант. Хорошо. Третий вариант действительно не кажется мне разумным.). Не знаю, как они реализуют замыкания в настоящее время в Java, я не следил за новинками о Java.

2 голосов
/ 10 октября 2013

Я думаю, что динамическая область видимости в Common LISP является аналогом глобальной переменной в C. Использование их в функциональных функциях проблематично.

1 голос
/ 23 августа 2013

Эта классическая статья Ричарда Столлмана (из GNU / Linux, Emacs, FSF) объясняет, почему динамическая область видимости важна для редактора Emacs и языка Emacs Lisp. В целом, это полезно для настройки.

http://www.gnu.org/software/emacs/emacs-paper.html#SEC17

См. Также эту страницу в вики Emacs, для получения дополнительной информации об использовании динамического определения объема в Emacs Lisp:

1 голос
/ 10 ноября 2010

Динамические перерывы в определении объема Ссылочная прозрачность , что означает, что вы больше не можете рассуждать о программе. DS в основном глобальные переменные на стероидах.

1 голос
/ 03 мая 2009

Динамически изменяемые переменные являются мощным, но иногда не слишком понятным и опасным инструментом.

Представьте, что вы хотите иметь глобальные переменные, специфичные для потока, т. Е. Каждый поток имеет свой собственный набор глобальных переменных. Это легко сделать с помощью динамического объема. Просто измените ссылки на эти переменные при инициализации потока.

Или подумайте об исключениях: они динамически ограничены в большинстве языков. Если бы вам пришлось создавать систему исключений с нуля, вы могли бы легко сделать это с помощью динамически изменяемых переменных.

0 голосов
/ 24 августа 2013

Пример, который мне удобен при привязке Emacs - не уверен, является ли лексический или динамический правильный термин.

Переменная, ограниченная внутри let, рассматривается как нисходящая, без явной передачи в качестве аргумента, что экономит много нажатий клавиш.

(defun foo1 ()
  (message "%s" a))

(defun foo2 ()
  (let ((a 2))
  (message "%s" a)))

(defun foo3 ()
  (let ((a 1))
    (foo1)
    (foo2)))

==>
1
2

Интерес представляет привязка внутри foo2, поскольку здесь могут быть установлены значения по умолчанию

(пусть ((a (если (eq что-то)) назначить иначе ...

...