動機
pkg
関数呼び出しによって生成されたいくつかのオブジェクトを実行中のキャッシュに収集する R パッケージ (と呼びます) を開発しています。名前空間でキャッシュをオブジェクトとして実装するのは簡単ですlist
(それを と呼びます.cache
) 。pkg
ただし、ユーザーがキャッシュに直接干渉するのを防ぎたいと思います。これは、:::
構文を介して常に公開できますpkg:::.cache
。
つまり.cache
、オブジェクト指向プログラミングのプライベート フィールドと同様に保護したいと考えています。すべての操作は、「API フレーバー」を持つ ed 関数.cache
によって排他的に呼び出される内部ヘルパー関数によって実行する必要があります。@export
問題
そのため、名前空間でオブジェクトを定義するenvironment
(それを と呼ぶ) という考えがあったので、... myを my に.vault
入れることができます。.cache
.vault
私の困惑は、次のような環境が R で参照によって.vault
機能する数少ないものの 1 つであるということです。そのため、またはその内容を表示だけでなく変更にも公開することを恐れています。アクセサー関数を変更して、そのような露出を有効にしないようにすることはできますが、その場で直接変更できる場合、そのような努力はすべて無駄です。pkg:::.vault
.vault
pkg:::.get_cache()
.vault
走るな
例として、以下の危険な(?) コードについて考えてみましょう。最初に、「ターゲットを特定する」ために.S3MethodsClasses
から内部環境を調べます。dplyr
dplyr:::.S3MethodsClasses
#> <environment: 0x7fab9c6c5310>
ls(dplyr:::.S3MethodsClasses)
#> [1] "grouped_df" "rowwise_df"
次に、オブジェクトを調べrowwise_df
て、価値のある「ターゲット」と見なします。
dplyr:::.S3MethodsClasses$rowwise_df
#> Virtual Class "rowwise_df" [package "dplyr"]
#>
#> Slots:
#>
#> Name: .Data names row.names
#> Class: list character data.frameRowLabels
#>
#> Name: .S3Class
#> Class: character
#>
#> Extends:
#> Class "tbl_df", directly
#> Class "tbl", by class "tbl_df", distance 2
# ...
dplyr
最後に、名前空間のほとんどのオブジェクトとは異なり...
library(dplyr)
mutate <- NULL
dplyr::mutate
#> function (.data, ...)
#> {
#> UseMethod("mutate")
#> }
#> <bytecode: 0x7fab9c2f6120>
#> <environment: namespace:dplyr>
... .S3MethodsClasses
points by referenceのような環境なので、その内容をその場で簡単に変更できます。
# "Copy" the pointer to allow `<-` assignment.
same_pointer <- dplyr:::.S3MethodsClasses
same_pointer
#> <environment: 0x7fab9c6c5310>
# Modify in place.
same_pointer$rowwise_df <- NULL
dplyr:::.S3MethodsClasses$rowwise_df
#> NULL
そのまま「金庫」が奪われる!
疑惑
答えはlockEnvironment()
友人と一緒にここにあるのではないかと思いますが、アプリケーションは私を少し超えています. おそらく、環境.onLoad
をセットアップするために何かを行うことができます。これは、それ自体とその中のバインディングの両方を edにしますが、名前空間内に入力される とアクセサー functionの間のアクティブなバインディングを作成する前ではありません。.vault
lock*()
.vault
.cache
.get_cache()
pkg
ノート
名前空間.get_cache()
から仲間の関数の外部で呼び出されたときのように、(ヘルパー) 関数を終了する機能を既に開発しています。pkg
したがって、 を公開するpkg:::.get_cache()
と、ユーザーは.get_cache()
手動で操作したり、独自のカスタム関数で操作したりできなくなります。
正規性
正規の回答を提供するのに十分な経験を積んだ R 開発者のアドバイス (もしあれば) に特に感謝します。