container/adapters の設計
設計目標
container パッケージは、どの具体的な型にも依存せずに能力を定義します。リポジトリ自身の型に対する辞書は誰かが提供しなければならず、そのコードは能力のレコードとすべての具体的パッケージの両方を参照する必要があります。その場所が container/adapters です。適応対象のすべてに依存する末端パッケージであり、これによって他のパッケージはそうした依存を持たずに済みます。
数学的背景
アダプタは、具体的な型がコンテナモデルの抽象的なオブジェクトを 表現 していることの根拠です(container の設計 を参照)。型 V について、アダプタは length と get を通じて表示 を与え、可能な場合は tabulate を通じてその切断を与えます。
ビューの場合、表示は形状 の元の行列 から計算されます。
ビューには tabulate がありません。構築しようとすると元の行列を作らなければならず、その結果はもはや呼び出し側が持つ何かのビューではなくなるからです。ビューの可変な編集は に書き込みます。これこそがビューの目的です。
設計上の判断
独立した末端パッケージ
問題。 container にアダプタを含めると、immut、mutable、backends/default に依存することになり、能力のレコードだけが欲しい外部ライブラリまで、すべての具体的な型を取り込むことになります。
決定。 レコードとアルゴリズムは error にだけ依存する container に置きます。アダプタは container/adapters に置き、これは container、immut、mutable、backends/default に依存します。リポジトリのどのパッケージもアダプタには依存しません。
理由。 こうすると依存は特殊なものから一般的なものへ向かいます。外部ライブラリは 統合ガイド に従い、container だけを相手に独自の辞書を公開します。
型と能力ごとに 1 つのファクトリ
各ファクトリは <type>_<capability>_ops という形の名前を持ち、新しいレコードを返します。自由な型パラメータを持つ総称関数は値として保存できないため、「すべての T に対する @immut.Matrix[T] の読み取り辞書」を提供するにはファクトリ関数を使います。読み取り、構築、編集は要素を調べないので、ファクトリは T に制約を課しません。
編集モデルは所有に従う
不変な型とそのラッパーには永続的な編集を、可変な型・ビュー・可変なラッパーには可変な編集を提供します。可変な行列に永続的な編集を提供すると set ごとに全体のコピーが必要になり、 に見える呼び出しの裏に のコストを隠すことになります。不変な行列に可変な編集を提供することは、その値の意味論を壊さない限り不可能です。
委譲する前に検証する
具体的な型は不正なインデックスで中断します。各アダプタはまずインデックスや形状を検査してエラー値を返すので、呼び出すメソッドが中断しうるにもかかわらず、辞書は container の panic しない契約を満たします。
正しさと不変条件
- すべての読み取りアダプタは、有効なインデックスでは を、それ以外では
IndexOutOfBoundsを満たします。ビルダーは上記のtabulate/getの法則を満たします。 - ビルダーは初期化関数を各要素についてちょうど 1 回、行優先順に呼び出します。
- 永続的な編集は引数を決して変更しません。
@immutの更新は永続ベクトルのパスコピーです。 - ビューの可変な編集は元の行列だけを変更し、それ以外は変更しません。
- すべてのファクトリは で実行されます。辞書の呼び出しのコストは元のメソッドのコストと同じです(
@mutableの読み取りは 、@immutは )。
却下した代替案
- 各具体的パッケージの中にアダプタを置く。 そうすると
immutとmutableが実験的なcontainer層に依存することになり、安定した具体的 API がその不安定さを受け継いでしまいます。 - 外部の型に対するアダプタ。 このリポジトリには自身が保守する型のアダプタだけを含めます。外部ライブラリは自身のアダプタを所有します。
境界
このパッケージは能力もアルゴリズムも追加せず、既存の型に対する根拠だけを提供します。ビューに対する構築辞書、可変な型に対する永続的な編集、このリポジトリ外の型に対するアダプタは提供しません。取り下げられた OpenBLAS バックエンドのアダプタは、そのバックエンドとともに contrib/openblas_backend に保存されており、このパッケージには含まれません。