私は Roslyn CTP を調べていますが、これは Expression tree API と同様の問題を解決しますが、どちらも不変ですが、Roslynはまったく異なる方法でこれを行います:
Expression
ノードには親ノードへの参照がなく、ExpressionVisitor
を使用して変更されます。そのため、大きなパーツを再利用できます。
反対側のRoslynのSyntaxNode
には、その親への参照があるため、すべてのノードは事実上、再利用できないブロックになります。 Update
、ReplaceNode
などのメソッドは、変更を行うために提供されています。
これはどこで終わりますか? Document
? Project
? ISolution
? APIは(ボタンを押すのではなく)ツリーの段階的な変更を促進しますが、各ステップは完全なコピーを作成しますか?
なぜ彼らはそのような選択をしたのですか?私が見逃している興味深いトリックはありますか?
更新:この質問は 2012年6月8日の私のブログの主題 でした。すばらしい質問をありがとう!
すばらしい質問です。私たちはあなたが提起する問題について長い間議論しました。
次の特性を持つデータ構造が必要です。
persistence とは、テキストバッファに対して編集が行われたときに、ツリー内の既存のノードのほとんどを再利用する機能を意味します。ノードは不変なので、それらを再利用するための障壁はありません。これはパフォーマンスのために必要です。キーを押すたびにファイルの膨大な数のウォッジを再解析することはできません。編集の影響を受けたツリーの部分だけを再Lexして再解析する必要があります。
これら5つすべてを1つのデータ構造に入れようとすると、すぐに問題が発生します。
しかし、Roslynチームでは、不可能なことを日常的に行っています。実際には、 two 解析ツリーを保持することで、不可能を実現しています。 「グリーン」ツリーは不変で永続的であり、親参照はなく、「ボトムアップ」で構築され、すべてのノードはその width を追跡しますが、 absoluteは追跡しません位置。編集が発生すると、編集の影響を受けた緑のツリーの部分のみが再構築されます。これは、通常、ツリー内の解析ノードの総数の約O(log n)です。
「赤い」木は不変の facade で、緑の木の周りに構築されます。 「トップダウン」オンデマンドで構築され、すべての編集で破棄されます。親参照は、ツリーを上から下に降りながらオンデマンドで製造することで計算されます。また、下降すると、幅から絶対位置を計算して、絶対位置を作成します。
ユーザーであるあなたには、赤い木しか見えません。緑の木は実装の詳細です。解析ノードの内部状態を覗くと、実際には別のタイプの another 解析ノードへの参照があることがわかります。これが緑のツリーノードです。
ちなみに、これらは「赤/緑の木」と呼ばれます。これらは、設計会議でデータ構造を描画するために使用したホワイトボードマーカーの色でした。色に他の意味はありません。
この戦略の利点は、不変性、永続性、親参照など、これらすべての優れた機能を利用できることです。コストは、このシステムが複雑であり、「赤い」ファサードが大きくなると、大量のメモリを消費する可能性があることです。現在、利益を失うことなくコストを削減できるかどうかを確認するための実験を行っています。