Текущая углубленная документация по привязке переменных предназначена для Rebol 2. Может ли кто-нибудь предоставить резюме различий между Rebol 2 и 3?
Каково краткое изложение различий в отношении поведения привязки между Rebol 2 и 3?
Ответ 1
На самом деле на самом деле нет резюме, поэтому давайте рассмотрим основы, возможно, немного более неформально, чем Bindology. Пусть Ладислав написал новую версию своего трактата для R3 и Red. Мы просто рассмотрим основные различия в порядке важности.
Контексты объектов и функций
Здесь большая разница.
В R2 были в основном два вида контекстов: контексты обычных объектов и system/words
. Оба имеют статические привязки, а это означает, что после выполнения функции bind
привязка слова указывала на конкретный объект с реальным указателем.
Контекст system/words
мог быть расширен во время выполнения, чтобы включить новые слова, но все остальные объекты не были. В функциях используются обычные контексты объектов, с некоторыми хакерами, чтобы вызывать блоки значений, когда вы вызываете функцию рекурсивно.
Слово self
было просто обычным словом, которое произошло с первым в объектных контекстах, с отображением экрана, чтобы не показывать первое слово в контексте; в контекстах функции не было этого слова, поэтому они не отображали правильное правильное слово.
В R3 почти все это отличается.
В R3 существуют также два вида контекстов: Regular и stack-local. Регулярные контексты используются объектами, модулями, циклами привязки, use
, в основном все, кроме функций, и они расширяемы, как system/words
(да, "было", мы доберемся до этого). Старые объекты фиксированной длины исчезли. Функции используют стек-локальные контексты, которые (запрещая любые ошибки, которые мы еще не видели) не должны расширяться, потому что это испортит кадры стека. Как и в случае с старым system/words
, вы не можете сжимать контексты, потому что удаление слов из контекста нарушает любые привязки этих слов.
Если вы хотите добавить слова в обычный контекст, вы можете использовать bind/new
, bind/set
, resolve/extend
или append
или другие функции, вызывающие их, в зависимости от того, какое поведение вам нужно. Это новое поведение для функций bind
и append
в R3.
Привязывание слов к регулярным и стек-локальным контекстам статично, как и раньше. Ценностный поиск - другое дело. Для регулярных контекстов значение look-up довольно прямое, сделанное простым указателем указателя на статический блок слотов значений. Для локальных контекстов стека блок значений связан с фреймом стека и ссылается оттуда, поэтому, чтобы найти правильный кадр, вам нужно выполнить стек, который равен O (глубина стека). См. ошибка # 1946 - мы поймем, почему позже.
О, а self
больше не является обычным словом, это связующее трюк, ключевое слово. Когда вы связываете блоки слов с объектами или контекстами модулей, он связывает ключевое слово self
, которое оценивает как ссылку на контекст. Тем не менее, существует внутренний флаг, который может быть установлен, который говорит, что контекст "бескорыстный", который отключает ключевое слово self
. Когда это ключевое слово отключено, вы можете использовать слово self
как поле в своем контексте. Циклы привязки, use
и контексты функций устанавливают самоотверженный флаг для их контекстов, и функция selfless?
проверяет это.
Эта модель была уточнена и задокументирована в довольно вовлеченной пламенной войне CureCode, так же, как модель R2 была задокументирована планами REBOL по рассылке в 1999-2000 годах.: -)
Функции против закрытий
Когда я говорил о контекстах локальных стеков, я имел в виду контексты, используемые функциями типа function!
. R3 имеет много типов функций, но большинство из них являются встроенными функциями так или иначе, а собственные функции не используют эти контексты в стеке (хотя они и получают стоп-фреймы). Единственными типами функций для кода Rebol являются function!
и новый тип closure!
. Закрытия сильно отличаются от обычных функций.
Когда вы создаете function!
, вы создаете функцию. Он создает стек-локальный контекст, связывает тело кода с ним и объединяет тело кода и спецификацию. Когда вы вызываете функцию, она создает кадр стека со ссылкой на контекст функции и запускает блок кода. Если он имеет слова доступа в контексте функции, он выполняет стек, чтобы найти правильный фрейм, а затем получает значения оттуда. Довольно справедливо.
Когда вы создаете closure!
, с другой стороны, вы создаете конструктор функций. Он устанавливает тело спецификации и функции почти так же, как function!
, но когда вы вызываете замыкание, он создает новый регулярный самоотверженный контекст, затем выполняет bind/copy
тела, меняя все ссылки на контекст функции ссылки на новый регулярный контекст в копии. Затем, когда он копирует тело, все ссылки на замыкание являются такими же статическими, как и для контекстов объектов.
Другое различие между ними заключается в том, как они ведут себя до того, как функция работает, а функция запущена, и после того, как функция выполнена.
В R2 контексты function!
все еще существуют, когда функция не запущена, но блок значений вызова верхнего уровня функции по-прежнему сохраняется. Только рекурсивные вызовы получают новые блоки значений, вызов верхнего уровня сохраняет постоянный блок значений. Как я уже сказал, хакерство. Хуже того, блок значений верхнего уровня не очищается, когда функция возвращается, поэтому вам лучше убедиться, что вы не ссылаетесь на что-либо чувствительное или что вы хотите перерабатывать при возврате функции (используйте функцию also
для очистки, что я сделал для этого).
В R3 контексты function!
все еще существуют, когда функция не запущена, но блок значений вообще не существует. Все вызовы функций действуют как рекурсивные вызовы, сделанные в R2, но лучше, потому что они разработаны таким образом полностью вниз, ссылаясь на фрейм стека. Объем этого фрейма стека является динамическим (преследуйте поклонника Lisp, если вам нужна история этого), поэтому пока функция работает в текущем стеке (да, "текущий", мы доберемся до этого), вы можете использовать одно из своих слов, чтобы получить значения самого последнего вызова этой функции. Как только все вложенные вызовы функции будут возвращены, в области не будет никаких значений, и вы просто вызовете ошибку (неправильная ошибка, но мы это исправим).
Там также бесполезное ограничение на привязку к функциональному слову вне сферы видимости, которое находится в моем списке задач, чтобы исправить в ближайшее время. См. ошибка # 1893.
Для функций closure!
перед запуском замыкания контекст вообще не существует. Как только закрытие начинает работать, контекст создается и существует настойчиво. Если вы снова вызываете закрытие или рекурсивно, создается другой постоянный контекст. Любое слово, которое вытекает из замыкания, относится только к контексту, созданному во время этого конкретного запуска замыкания.
Вы не можете получить слово, связанное с контекстом функции или закрытия в R3, когда функция или закрытие не запущены. Для функций это проблема безопасности. Для закрытий это проблема определения.
Закрытия считались настолько полезными, что мы с Ладиславом поместили их в R2, независимо в разное время, в результате чего был подобным кодом, странно. Я думаю, что версия Ladislav предшествовала R3 и послужила источником вдохновения для типа R3 closure!
; моя версия была основана на проверке внешнего поведения этого типа и попытке реплицировать его в R2 для R2/Forward, поэтому забавно, что решение для closure
оказалось настолько похоже на оригинал Ladislav, которого я не видел до тех пор, пока гораздо позже. Моя версия включалась в сам R2, начиная с 2.7.7, как функции closure
, to-closure
и closure?
, а слову closure!
присваивается то же значение типа, что и function!
в R2.
Глобальные и локальные контексты
Здесь, где вещи становятся действительно интересными.
В Bindology было довольно большое количество статей, в которых говорилось о различии между "глобальный" контекст (который оказался system/words
) и "локальный" контексты, довольно важное различие для R2. В R3 это различие не имеет значения.
В R3, system/words
исчез. Нет ни одного "глобального" контекста. Все регулярные контексты являются "локальными" в том смысле, что это означало в R2, что делает этот смысл "локальным" бесполезным. Для R3 нам нужен новый набор термов.
Для R3 единственное различие, которое имеет значение, заключается в том, являются ли контексты ориентированными на задачи, поэтому единственное полезное значение для "глобальных" контекстов - это те, которые не относятся непосредственно к задачам, а "локальные" контексты - это те, которые являются задача-относительна. "Задачей" в этом случае будет тип task!
, который в основном является потоком ОС в текущей модели.
В R3 на данный момент единственными до сих пор являются относительные задачи (едва ли) - это переменные стека, что означает, что контексты с атрибутами стека также должны относиться к задаче. Вот почему необходим system/contexts/user в основном является самым близким к тому, что R3 имеет значение R2 system/words
, это означает, что сценарии, которые считаются их "глобальным" контекстом, на самом деле должны быть локальными в R3.
У R3 есть пара системных глобальных контекстов, называемых sys
и lib
, хотя они используются совершенно иначе, чем глобальный контекст R2. Кроме того, все контексты модулей являются глобальными.
Возможно (и распространено), что существуют глобально определенные контексты, на которые ссылаются только ссылки на локальные корневые ресурсы, поэтому эти контексты будут действовать косвенно локально на основе задач. Это то, что обычно происходит, когда привязка циклов, use
, закрытий или частных модулей вызывается из "кода пользователя", что в основном означает немодульные скрипты, которые привязаны к system/contexts/user
. Технически это также относится к функциям, называемым также модулями (поскольку функции являются стек-локальными), но эти ссылки в конечном итоге получают привязку к модулям, которые являются глобальными.
Нет, у нас еще нет синхронизации. Тем не менее, модель, которую R3-дизайн, как предполагается, в конечном итоге имеет, и отчасти уже делает. Подробнее см. Статью о привязке к модулю.
В качестве бонуса R3 теперь имеет настоящую таблицу символов вместо того, чтобы использовать system/words
как специальную таблицу символов. Это означает, что предел слова R2, который был использован довольно быстро, эффективно ушел в R3. Я не знаю ни одного приложения, которое достигло нового предела, или даже определило, насколько высока предел, хотя, по-видимому, он намного превосходит многие миллионы различных символов. Мы должны проверить источник, чтобы понять это, теперь, когда у нас есть доступ к нему.
НАГРУЗКА И ИСПОЛЬЗОВАНИЕ
Незначительные детали. Функция use
инициализирует свои слова с помощью none
вместо того, чтобы оставить их неустановленными. И поскольку нет "глобального" контекста, как есть в R2, load
не обязательно связывает слова вообще. Какой контекст load
связывается в зависимости от обстоятельств, упомянутых в Статья привязки модуля, хотя, если вы не указали иначе, явно привязывает слова к system/contexts/user
. И оба теперь являются мезонинными функциями.
Правописание и псевдонимы
R3 в основном совпадает с R2 в этом случае, привязки слов по умолчанию нечувствительны к регистру. Сами слова сохраняются в случае, и если вы их сравниваете с помощью чувствительных к регистру методов, вы увидите различия между словами, которые отличаются только случаем.
В контексте объектов или функций, хотя, когда слово отображается в слот значения, тогда другое слово привязано к этому контексту или просматривается во время выполнения, слова, которые отличаются только случаем, считаются фактически одним и тем же словом и картой в тот же слот значения.
Однако было обнаружено, что явно созданные псевдонимы, выполненные с помощью функции alias
, где орфография псевдонимов отличается друг от друга другими способами, а не просто по-разному разбивает объектные и функциональные контексты. В R2 они разрешили эти проблемы в system/words
, что сделало alias
просто слишком неудобным для использования в чем-либо, кроме демонстрации, а не в качестве опасного.
Из-за этого мы полностью удалили внешнюю видимую функцию alias
. Внутренний псевдоним все еще работает, потому что он только псевдонизирует слова, которые обычно считаются эквивалентными для контекстного поиска, а это означает, что контексты не прерываются. Но теперь мы рекомендуем, чтобы локализация и другие трюки, которые alias
использовались в демонстрационных версиях, если их никогда не было на практике, выполнялись с использованием старомодного метода присвоения значений другому слову с новой орфографией.
Типы слов
Тип issue!
теперь является типом слова. Вы можете связать его. До сих пор никто не воспользовался возможностью связывания проблем, а просто использовал увеличенную скорость операций.
Это в значительной степени, для преднамеренных изменений. Большинство остальных различий могут быть побочными эффектами вышеупомянутых или, возможно, даже ошибок или еще не реализованных функций. В R3 может быть даже некоторое поведение, подобное R2, что также является результатом ошибок или еще не реализованных функций. Когда вы сомневаетесь, спросите сначала.