可変バインディングターゲットRebol2に関する現在の詳細なドキュメント。誰かがRebol2と3の違いの要約を提供できますか?
1 に答える
どこかに要約が実際にはないので、おそらくBindologyよりも少し非公式に基本を調べてみましょう。LadislavにR3とRedに関する彼の論文の新しいバージョンを書かせてください。重要度の高い順に、基本的な違いについて説明します。
オブジェクトと関数のコンテキスト
これが大きな違いです。
R2には、基本的に2種類のコンテキストがありました。通常のオブジェクトコンテキストとsystem/words
。どちらにも静的バインディングがありました。つまり、bind
関数が実行されると、バインディングという単語は実際のポインターを持つ特定のオブジェクトを指していました。
system/words
コンテキストは実行時に拡張して新しい単語を含めることができましたが、他のすべてのオブジェクトはそうではありませんでした。関数は通常のオブジェクトコンテキストを使用し、関数を再帰的に呼び出すときに値ブロックを切り替えるためのハッカーがいくつかありました。
このself
単語は、オブジェクトコンテキストの最初の単語に発生した通常の単語であり、コンテキストの最初の単語を表示しないように表示ハックされています。関数コンテキストにはその単語がなかったため、最初の通常の単語が正しく表示されませんでした。
R3では、そのほとんどすべてが異なります。
R3には、通常とスタックローカルの2種類のコンテキストもあります。通常のコンテキストは、オブジェクト、モジュール、バインディングループ、use
基本的には関数以外のすべてで使用され、以前のようsystem/words
に拡張可能です(はい、「だった」、これについて説明します)。古い固定長オブジェクトはなくなりました。関数はスタックローカルコンテキストを使用しますが、これは(まだ見たことがないバグを除いて)スタックフレームを台無しにするため、拡張可能であるとは考えられていません。古いものと同様に、system/words
コンテキストを縮小することはできません。コンテキストから単語を削除すると、それらの単語のバインドが壊れてしまうためです。
通常のコンテキストに単語を追加する場合はbind/new
、必要な動作に応じて、、、、、またはそれらを呼び出す他の関数を使用bind/set
できます。これは、R3のおよび関数の新しい動作です。resolve/extend
append
bind
append
通常のコンテキストとスタックローカルコンテキストへの単語のバインドは、以前と同様に静的です。価値の検索は別の問題です。通常のコンテキストでは、値のルックアップは非常に直接的であり、値スロットの静的ブロックへの単純なポインター間接参照によって実行されます。スタックローカルコンテキストの場合、値ブロックはスタックフレームによってリンクされ、そこから参照されるため、適切なフレームを見つけるには、O(スタック深度)であるスタックウォークを実行する必要があります。詳細については、バグ#1946を参照してください。理由については後で説明します。
ああ、そしてself
もう普通の言葉ではありません、それは拘束力のあるトリック、キーワードです。単語のブロックをオブジェクトまたはモジュールコンテキストにバインドするself
と、コンテキストへの参照であると評価されるキーワードがバインドされます。ただし、コンテキストが「無私」であることを示す設定可能な内部フラグがあり、そのself
キーワードがオフになります。そのキーワードがオフになっている場合、実際にその単語self
をコンテキストのフィールドとして使用できます。バインディングループuse
と関数コンテキストは、それらのコンテキストに無私のフラグを設定し、selfless?
関数はそれをチェックします。
このモデルは、R2のモデルが1999年から2000年にREBOLメーリングリストの炎上戦争によって文書化されたように、かなり複雑なCureCode炎上戦争で洗練され文書化されました。:-)
機能とクロージャ
上記のスタックローカル関数コンテキストについて話していたとき、私はfunction!
型関数によって使用されるコンテキストを意味していました。R3には多くの関数型がありますが、それらのほとんどは何らかの形でネイティブ関数であり、ネイティブ関数はこれらのスタックローカルコンテキストを使用しません(スタックフレームを取得しますが)。Rebolコード用の関数型はfunction!
と新しいclosure!
型だけです。クロージャは通常の機能とは大きく異なります。
を作成するfunction!
と、関数が作成されます。スタックローカルコンテキストを構築し、コード本体をそれにバインドし、コード本体と仕様をバンドルします。関数を呼び出すと、関数のコンテキストへの参照を含むスタックフレームが作成され、コードブロックが実行されます。関数コンテキストにアクセスワードがある場合は、スタックウォークを実行して適切なフレームを見つけ、そこから値を取得します。かなり簡単です。
closure!
一方、を作成する場合は、関数ビルダーを作成します。仕様と関数本体をとほぼ同じように設定しますが、クロージャfunction!
を呼び出すと、新しい通常の無私のコンテキストを作成し、次にbind/copy
本体のを実行して、関数コンテキストへのすべての参照を新しい通常のコンテキストへの参照に変更しますコピーで。次に、コピーされた本文を実行すると、すべてのクロージャーワード参照はオブジェクトコンテキストの参照と同じくらい静的になります。
2つの違いは、関数の実行前、関数の実行中、および関数の実行後の動作にあります。
R2ではfunction!
、関数が実行されていないときでもコンテキストは存在しますが、関数の最上位呼び出しの値ブロックも存続します。再帰呼び出しのみが新しい値ブロックを取得し、トップレベルの呼び出しは永続的な値ブロックを保持します。私が言ったように、ハッカリー。さらに悪いことに、関数が戻ったときに最上位の値ブロックがクリアされないため、機密性の高いものを参照していないこと、または関数が戻ったときにリサイクルしたいことを確認することをお勧めします(also
関数を使用してクリーンアップします、それが私ですのために作った)。
R3では、function!
関数が実行されていないときでもコンテキストは存在しますが、値ブロックはまったく存在しません。すべての関数呼び出しは、R2で行った再帰呼び出しと同じように機能しますが、スタックフレームを参照するように設計されているため、より優れています。そのスタックフレームのスコープは動的であり(その履歴が必要な場合はLispファンをストーカーします)、関数が現在のスタックで実行されている限り(はい、「現在」、それに到達します)、その単語の1つを使用して、その関数の最新の呼び出しの値を取得できます。関数のネストされたすべての呼び出しが返されると、スコープに値がなくなり、エラーがトリガーされるだけです(間違ったエラーですが、修正します)。
すぐに修正するために私のtodoリストにある範囲外の機能語へのバインドにも役に立たない制限があります。詳細については、バグ#1893を参照してください。
関数の場合closure!
、クロージャが実行される前は、コンテキストはまったく存在しません。クロージャーの実行が開始されると、コンテキストが作成され、永続的に存在します。クロージャを再度、または再帰的に呼び出すと、別の永続コンテキストが作成されます。クロージャからリークする単語は、クロージャの特定の実行中に作成されたコンテキストのみを指します。
関数またはクロージャが実行されていない場合、R3の関数またはクロージャコンテキストにバインドされた単語を取得することはできません。関数の場合、これはセキュリティの問題です。クロージャの場合、これは定義上の問題です。
クロージャは非常に便利であると考えられていたため、Ladislavと私は両方ともR2に移植しましたが、異なる時間に独立して、奇妙なことに同様のコードが生成されました。LadislavのバージョンはR3よりも前のものであり、R3のclosure!
タイプのインスピレーションとなったと思います。私のバージョンは、そのタイプの外部動作をテストし、R2 / Forward用にR2で複製しようとしたことに基づいていたので、ソリューションclosure
がLadislavのオリジナルと非常に似ていることになったのはおもしろいです。私のバージョンは、2.7.7以降のR2自体に、、および関数として含まれclosure
、to-closure
単語closure?
にはR2closure!
と同じタイプ値が割り当てられますfunction!
。
グローバルコンテキストとローカルコンテキスト
ここで物事は本当に興味深いものになります。
Bindologyには、「グローバル」コンテキスト( R2のかなり重要な違い)と「ローカル」コンテキストの違いについて説明している記事がかなりたくさんありました。system/words
R3では、その区別は関係ありません。
R3では、system/words
なくなりました。「グローバル」コンテキストは1つではありません。すべての通常のコンテキストは、R2で意味された意味で「ローカル」であり、「ローカル」の意味は役に立たなくなります。R3の場合、新しい用語のセットが必要です。
R3の場合、重要な唯一の違いは、コンテキストがタスク相対であるかどうかです。したがって、「グローバル」コンテキストの唯一の有用な意味は、直接タスク相対ではないコンテキストであり、「ローカル」コンテキストは、タスク相対であるコンテキストです。 。この場合の「タスク」はtask!
タイプであり、基本的には現在のモデルのOSスレッドです。
R3では、現時点では、これまでのところタスク相対(かろうじて)であるのはスタック変数だけです。つまり、スタック相対関数コンテキストもタスク相対であると想定されています。これがスタックウォークが必要な理由です。そうしないと、すべての単一の関数コンテキストでTLSポインターを保持および維持する必要があるためです。通常のコンテキストはすべてグローバルです。
考慮すべきもう1つのことは、計画(これまでのところほとんど実装されていない)によれば、ユーザーコンテキストsystem/contexts/user
とsystem
それ自体もタスク相対であることが意図されているため、R3標準でも「ローカル」と見なされることです。そして、これsystem/contexts/user
は基本的にR3がR2に最も近いものであるため、スクリプトが「グローバル」コンテキストであると見なすものは、実際にはR3ではタスクローカルsystem/words
であると想定されていることを意味します。
R3にはとと呼ばれるシステムグローバルコンテキストがいくつかありますsys
がlib
、それらはR2のグローバルコンテキストとはまったく異なる方法で使用されます。また、すべてのモジュールコンテキストはグローバルです。
タスクローカルルート参照からのみ参照されるグローバルに定義されたコンテキストが存在する可能性があります(一般的です)。そのため、これらのコンテキストは間接的にタスクローカルになります。これは、バインディングループ、use
クロージャ、またはプライベートモジュールが「ユーザーコード」から呼び出されたときに通常発生することです。これは、基本的に、にバインドされる非モジュールスクリプトを意味しsystem/contexts/user
ます。技術的には、これはモジュールから呼び出される関数にも当てはまります(関数はスタックローカルであるため)が、これらの参照は最終的にグローバルなモジュールワードに割り当てられることがよくあります。
いいえ、まだ同期もありません。それでも、それはR3の設計が最終的に持つことになっているモデルであり、部分的にはすでにそうなっています。詳細については、モジュールバインディングの記事を参照してください。
system/words
ボーナスとして、R3には、アドホックシンボルテーブルとして使用する代わりに、実際のシンボルテーブルがあります。これは、R2でかなり速くヒットするために使用されていた単語制限R2がR3で事実上なくなったことを意味します。明らかに何百万もの異なるシンボルをはるかに超えていますが、新しい制限に達した、または制限の高さを決定したアプリを私は知りません。ソースにアクセスできるようになったので、ソースをチェックしてそれを理解する必要があります。
ロードして使用する
マイナーな詳細。このuse
関数は、単語をnone
未設定のままにするのではなく、で初期化します。また、R2のように「グローバル」コンテキストがないため、load
必ずしも単語をバインドする必要はありません。どのコンテキストload
がバインドされるかは、モジュールバインディングの記事に記載されている状況によって異なりますが、特に指定しない限り、明示的に単語をにバインドしますsystem/contexts/user
。そして、両方ともメザニン機能になりました。
スペルとエイリアス
R3は基本的にこの点でR2と同じであり、単語のバインディングではデフォルトで大文字と小文字が区別されません。単語自体は大文字と小文字が区別され、大文字と小文字を区別する方法を使用して比較すると、大文字と小文字のみが異なる単語間の違いがわかります。
ただし、オブジェクトまたは関数のコンテキストでは、単語が値スロットにマップされると、別の単語がそのコンテキストにバインドされるか、実行時に検索されます。大文字と小文字だけが異なる単語は、事実上同じ単語と見なされ、同じ単語にマップされます。値スロット。
ただし、エイリアスされた単語のスペルが、オブジェクトと関数のコンテキストを大幅に壊しalias
た場合以外の方法で異なる関数で作成された、明示的に作成されたエイリアスが見つかりました。R2では、これらの問題をで解決しました。これは、積極的に危険ではなく、デモ以外で使用するにはあまりにも厄介なものでした。system/words
alias
このため、外部から見えるalias
機能を完全に削除しました。内部エイリアシング機能は、通常はコンテキストルックアップと同等と見なされる単語のみをエイリアシングするため、引き続き機能します。つまり、コンテキストが壊れることはありません。ただし、デモで使用されたローカリゼーションやその他のトリックalias
は、実際には行われない場合でも、新しいスペルで別の単語に値を割り当てるという昔ながらの方法を使用して行うことをお勧めします。
単語の種類
issue!
タイプは単語タイプになりました。あなたはそれをバインドすることができます。これまでのところ、操作の高速化を使用する代わりに、問題をバインドできることを利用した人は誰もいません。
意図的な変更については、これでほぼ完了です。残りの違いのほとんどは、上記の副作用である可能性があり、バグやまだ実装されていない機能である可能性もあります。R3には、バグやまだ実装されていない機能の結果でもあるR2のような動作が存在する場合もあります。疑問がある場合は、最初に尋ねてください。