［翻訳］R6 vignette: 移植可能R6クラスと移植不可R6クラス

この文書は，Winston Chang によるRパッケージ [`R6`](https://cran.r-project.org/package=R6) (version 2.2.0) のビネット ["Portable and non-portable R6 classes"](https://cran.r-project.org/package=R6/vignettes/Portable.html) の日本語訳です．

License: [MIT](https://opensource.org/licenses/MIT)

**関連文書**

- [R6クラス入門](http://qiita.com/nakamichi/items/d724468e0f716d7a174c)
- [移植可能R6クラスと移植不可R6クラス](http://qiita.com/nakamichi/items/b1240935894c2ca72c98)
- [R6オブジェクトのメソッドのデバッグ](http://qiita.com/nakamichi/items/97551ebc6bdfe1119cba)
- [R6と参照クラスの性能テスト](http://qiita.com/nakamichi/items/1841e7450a5621fa7142)

----



<!-- One limitation to R's reference classes is that class inheritance across package namespaces is limited. R6 avoids this problem when the `portable` option is enabled. -->

Rの参照クラスにおける限界のひとつは，パッケージの名前空間をまたいだクラス継承が制限されていることです．R6では，`portable`オプションを有効にするとこの問題が避けられます．

<!-- ## The problem -->

## 問題

<!-- Here is an example of the cross-package inheritance problem with reference classes: Suppose you have ClassA in pkgA, and ClassB in pkgB, which inherits from ClassA. ClassA has a method `foo()` which calls a non-exported function `fun()` in pkgA. -->

参照クラスでのパッケージ間継承における問題の例を示します．pkgAにClassAがあり，pkgBにはClassAを継承したClassBがあるとします．ClassAには，pkgAからエクスポートされていない関数`fun()`を呼び出す`foo()`メソッドがあるとします．

<!-- If ClassB inherits `foo()`, it will try to call `fun()` -- but since ClassB objects are created in pkgB namespace (which is an environment) instead of the pkgA namespace, it won't be able to find `fun()`. -->

ClassBが`foo()`を継承すれば`fun()`を呼び出そうと試みますが，ClassBはpkgAではなくpkgBの名前空間（環境）で作成されたものなので，`fun()`を見つけることができません．

<!-- Something similar happens with R6 when the `portable=FALSE` option is used. For example: -->

同様のことはR6で`portable=FALSE`と設定した場合にも起こります．例を示します．


```r
library(R6)
# 環境を作成してパッケージをシミュレートする
pkgA <- new.env()
pkgB <- new.env()

# pkgBではなく，pkgAに関数を作成する
pkgA$fun <- function() 10

ClassA <- R6Class("ClassA",
  portable = FALSE,
  public = list(
    foo = function() fun()
  ),
  parent_env = pkgA
)

# ClassBがClassAを継承する
ClassB <- R6Class("ClassB",
  portable = FALSE,
  inherit = ClassA,
  parent_env = pkgB
)
```
<!-- # Simulate packages by creating environments -->
<!-- # Create a function in pkgA but not pkgB -->
<!-- # ClassB inherits from ClassA -->

<!-- When we create an instance of ClassA, it works as expected: -->

ClassAのインスタンスを作成すると，期待通り動作します．


```r
a <- ClassA$new()
a$foo()
#> [1] 10
```

<!-- But with ClassB, it can't find the `foo()` function: -->

しかし，ClassBは`fun()`関数を見つけることができません．


```r
b <- ClassB$new()
b$foo()
#> Error in b$foo() : could not find function "fun"
```


<!-- ## Portable R6 -->

## 移植可能なR6

<!-- R6 supports inheritance across different packages, with the default `portable=TRUE` option. In this example, we'll again simulate different packages by creating separate parent environments for the classes. -->

R6はデフォルトでは`portable=TRUE`とすることで，異なるパッケージ間での継承をサポートしています．以下の例では，再びクラスの親環境を作成して，異なるパッケージをシミュレートしています．


```r
pkgA <- new.env()
pkgB <- new.env()

pkgA$fun <- function() {
  "この関数 `fun()` は pkgA にあります"
}

ClassA <- R6Class("ClassA",
  portable = TRUE,  # デフォルトの設定
  public = list(
    foo = function() fun()
  ),
  parent_env = pkgA
)

ClassB <- R6Class("ClassB",
  portable = TRUE,
  inherit = ClassA,
  parent_env = pkgB
)


a <- ClassA$new()
a$foo()
#> [1] "この関数 `fun()` は pkgA にあります"

b <- ClassB$new()
b$foo()
#> [1] "この関数 `fun()` は pkgA にあります"
```

<!-- When a method is inherited from a superclass, that method also gets that class's environment. In other words, method "runs in" the superclass's environment. This makes it possible for inheritance to work across packages. -->

メソッドがスーパークラスから継承されると，そのメソッドはスーパークラスの環境も取得します．言いかえると，メソッドはスーパークラスの環境の中で実行されます．これによってパッケージをまたいだ継承がうまく動作するようになります．

<!-- When a method is defined in the subclass, that method gets the subclass's environment. For example, here ClassC is a subclass of ClassA, and defines its own `foo()` method which overrides the `foo()` method from ClassA. It happens that the method looks the same as ClassA's -- it just calls `fun()`. But this time it finds `pkgC$fun` instead of `pkgA$fun`. This is in contrast to ClassB, which inherited the `foo()` method and environment from ClassA. -->

メソッドがサブクラスで定義されている場合には，そのメソッドはサブクラスの環境を取得します．たとえば，ClassCがClassAのサブクラスであり，ClassAの`foo()`メソッドをオーバーライドして独自の`foo()`メソッドを定義するものとします．このメソッドがたまたまClassAのメソッドと同じ見かけをしていて，単に`fun()`を呼び出すものであるとしましょう．しかしこの場合は`pkgA$fun()`ではなく`pkgC$fun()`が見つかることになります．`foo()`メソッドと環境をClassAから継承したClassBとは対照的です．


```r
pkgC <- new.env()
pkgC$fun <- function() {
  "この `fun()` は pkgC にあります"
}

ClassC <- R6Class("ClassC",
  portable = TRUE,
  inherit = ClassA,
  public = list(
    foo = function() fun()
  ),
  parent_env = pkgC
)

cc <- ClassC$new()
# このメソッドはClassCで定義されているのでpkgC$funが見つかる
cc$foo()
#> [1] "この `fun()` は pkgC にあります"
```
<!-- # This method is defined in ClassC, so finds pkgC$fun -->


<!-- ## Using `self` -->

## `self`の使用

<!-- One important difference between non-portable and portable classes is that with non-portable classes, it's possible to access members with just the name of the member, and with portable classes, member access always requires using `self$` or `private$`. This is a consequence of the inheritance implementation. -->

移植不可クラスと移植可能クラスの重要な違いは，移植不可クラスではメンバに対してメンバの名前だけでアクセスできますが，移植可能クラスではメンバへのアクセスに常に`self$`か`private$`が必要だということです．これは継承の実装方法からくる帰結です．

<!-- Here's an example of a non-portable class with two methods: `sety`, which sets the private field `y` using the `<<-` operator, and `getxy`, which returns a vector with the values of fields `x` and `y`: -->

二つのメソッドを持つ移植不可クラスの例を示します．`sety()`メソッドは`<<-`演算子を使ってプライベートフィールド`y`を設定するものであり，`getxy()`メソッドはフィールド`x`と`y`の値を持つベクトルを返すものです．


```r
NP <- R6Class("NP",
  portable = FALSE,
  public = list(
    x = 1,
    getxy = function() c(x, y),
    sety = function(value) y <<- value
  ),
  private = list(
    y = NA
  )
)

np <- NP$new()

np$sety(20)
np$getxy()
#> [1]  1 20
```

<!-- If we attempt the same with a portable class, it results in an error: -->

移植可能クラスで同じことを試みると誤った結果になります．


```r
P <- R6Class("P",
  portable = TRUE,
  public = list(
    x = 1,
    getxy = function() c(x, y),
    sety = function(value) y <<- value
  ),
  private = list(
    y = NA
  )
)

p <- P$new()

# エラーは出ないが，private$yは設定されず，グローバル環境のyが設定されてしまう！
# これは<<-のセマンティクスのせいである．
p$sety(20)
y
#> [1] 20

p$getxy()
#> Error in p$getxy() : object 'y' not found
```

<!-- # No error, but instead of setting private$y, this sets y in the global -->
<!-- # environment! This is because of the sematics of <<-. -->


<!-- To make this work with a portable class, we need to use `self$x` and `private$y`: -->

移植可能クラスでこれを動作させるには，`self$x`と`private$y`を使う必要があります．


```r
P2 <- R6Class("P2",
  portable = TRUE,
  public = list(
    x = 1,
    getxy = function() c(self$x, private$y),
    sety = function(value) private$y <- value
  ),
  private = list(
    y = NA
  )
)

p2 <- P2$new()
p2$sety(20)
p2$getxy()
#> [1]  1 20
```

<!-- There is a small performance penalty for using `self$x` as opposed to `x`. In most cases, this is negligible, but it can be noticeable in some situations where there are tens of thousands or more accesses per second. For more information, see the Performance vignette. -->

`x`ではなく`self$x`を使うと性能では少し損をします，この損失は大多数の場合においては無視できる程度ですが，秒間何万以上ものアクセスがあるような状況では顕在化することがあり得ます．さらなる情報については「性能」のビネットを見てください．

<!-- ## Potential pitfalls with cross-package inheritance -->

## パッケージ間継承の潜在的危険

<!-- Inheritance happens when an object is instantiated with `MyClass$new()`. At that time, members from the superclass get copied to the new object. This means that when you instantiate R6 object, it will essentially save some pieces of the superclass in the object. -->

継承はオブジェクトが`MyClass$new()`によってインスタンス化された時に起こります．この時，スーパークラスのメンバが新しいオブジェクトにコピーされます．これは要するに，R6オブジェクトをインスタンス化する時に，そのオブジェクトがスーパークラスの一部分を自身の中に保存するということです．

<!-- Because of the way that packages are built in R, R6's inheritance behavior could potentially lead to surprising, hard-to-diagnose problems when packages change versions. -->

Rのパッケージビルドの方法のせいで，パッケージのバージョンが変わる時に，R6での継承のふるまいが思いもよらない診断の難しい問題につながってしまうかもしれません．

<!-- Suppose you have two packages, pkgA, containing `ClassA`, and pkgB, containing `ClassB`, and there is code in pkgB that instantiates `ClassB` in an object, `objB`, at build time. This is in contrast to instantiating `ClassB` at run-time, by calling a function. All of the code in the package is run when a *binary* package is built, and the resulting objects are saved in the package. (Generally, if the object can be accessed with `pkgB:::objB`, this means it was created at build time.) -->

`ClassA`を含むpkgAと，`ClassB`を含むpkgBという二つのパッケージがあり，pkgBにはビルド時に`ClassB`をインスタンス化して`objB`というオブジェクトを作るコードが含まれているとしましょう．これは実行時に関数を呼び出して`ClassB`をインスタンス化するのとは対照的です．**バイナリ**パッケージがビルドされる際にはパッケージ内のすべてのコードが実行され，結果としてできたオブジェクトがパッケージ内に保存されます．（一般に，オブジェクトに`pkgB:::objB`でアクセスできるのであれば，それはビルド時に作成されたということです．）

<!-- When `objB` is created at package build time, pieces from the superclass, `pkgA::ClassA`, are saved inside of it. This is fine in and of itself. But imagine that pkgB was built and installed against pkgA 1.0, and then you upgrade to pkgA 2.0 without subsequently building and installing pkgB. Then `pkgB::objB` will contain some code from `pkgA::ClassA` 1.0, but the version of `pkgA::ClassA` that's installed will be 2.0. This can cause problems if `objB` inherited code which uses parts of `pkgA` that have changed -- but the problems may not be entirely obvious. -->

`objB`がビルド時に作成されると，スーパークラスである`pkgA::ClassA`の一部分が`objB`の中に保存されます．このこと自体には問題はありません．しかし，バージョン1.0のpkgAに対してpkgBのビルドとインストールを行った後に，pkgAをバージョン2.0に更新したが，その後pkgBのビルドとインストールは行わなかった，という状況を想像してみてください．すると，`pkgB::objB`はバージョン1.0の`pkgA::ClassA`のコードを含んでいるが，インストールされている`pkgA::ClassA`のバージョンは2.0だということになります．もし`objB`が`pkgA`の変更箇所を含むコードを継承していれば問題が起こり得ますが，見つけるのが難しい問題になるかもしれません．

<!-- This scenario is entirely possible when installing packages from CRAN. It is very common for a package to be upgraded without upgrading all of its downstream dependencies. As far as I know, R does not have any mechanism to force downstream dependencies to be rebuilt when a package is upgraded on a user's computer. -->

このシナリオはパッケージをCRANからインストールする時に起こる可能性があります．あるパッケージを更新する際に，そのパッケージに依存している下流側のパッケージは更新しないというのは非常によくあることです．私が知る限り，ユーザのコンピュータ上でパッケージが更新された際に，下流側で依存しているパッケージが再ビルドされるように強制する仕組みはRにはありません．

<!-- If this problem happens, the remedy is to rebuild pkgB against pkgA 2.0. I don't know if CRAN rebuilds all downstream dependencies when a package is updated. If it doesn't, then it's possible for CRAN to have incompatible binary builds of pkgA and pkgB, and users would then have to install pkgB from source, with `install.packages("pkgB", type = "source")`. -->

この問題が発生した場合の解決策は，pkgBをバージョン2.0のpkgAに対して再ビルドすることです．CRANでパッケージが更新される際に，下流側で依存しているすべてのパッケージが再ビルドされているのかどうか，私は知りません．もし再ビルドされていないのであれば，CRANにあるpkgAとpkgBのバイナリには互換性がなく，ユーザがpkgBをソースから`install.packages("pkgB", type = "source")`でインストールしなければならなくなる，ということがあり得ます．

<!-- To avoid this problem entirely, objects of `ClassB` must not be instantiated at build time. You can either instantiate them only in functions, or at package load time, by adding an `.onLoad` function to your package. For example: -->

この問題を完全に回避するには，`ClassB`のオブジェクトがビルド時にはインスタンス化されないようにしなければいけません．オブジェクトをインスタンス化するのは関数の中だけにするか，パッケージに`.onLoad()`関数を追加して，パッケージのロード時にインスタンス化するようにすればよいです．


```r
ClassB <- R6Class("ClassB",
  inherit = pkgA::ClassA,
  public = list(x = 1)
)

# ロード時に埋めるようにする
objB <- NULL

.onLoad <- function(libname, pkgname) {
  # 名前空間がロックされるのはロード後．ここではまだobjBを変更できる．
  objB <<- ClassB$new()
}
```
<!-- # We'll fill this at load time -->
<!-- # The namespace is locked after loading; we can still modify objB at this time. -->

<!-- You might be wondering why `ClassB` (the class, not the instance of the class `objB`) doesn't save a copy of `pkgA::ClassA` inside of it when the package is built. This is because, for the `inherit` argument, `R6Class` saves the unevaluated expression, (`pkgA::ClassA`), and evaluates it when `$new()` is called. -->

なぜパッケージのビルド時に`ClassB`（クラスのインスタンス`objB`ではなく，クラス）が`pkgA::ClassA`のコピーを自分の中に保存しないのか，不思議に思われるかもしれません．これはなぜかというと，`R6Class()`は`inherit`引数については未評価の表現式（`pkgA::ClassA`）を保存するようになっており，評価は`$new()`が呼び出された時に行うからです．


<!-- ## Wrap-up -->

## まとめ

<!-- In summary: -->

<!-- * Portable classes allow inheritance across different packages. -->
<!-- * Portable classes always require the use of `self` or `private` to access members. This can incur a small performance penalty, since using `self$x` is slower than just `x`. -->

まとめると

* 移植可能クラスでは異なるパッケージをまたいだ継承ができます
* 移植可能クラスではメンバにアクセスするのに常に`self`か`private`が必要です．`self$x`を使うと単に`x`とするより遅いため，性能では少し損をするかもしれません．

----

訳注：翻訳の際，コードは以下の環境で実行した．


```r
devtools::session_info()
#> Session info --------------------------------------------------------------
#>  setting  value                       
#>  version  R version 3.3.2 (2016-10-31)
#>  system   x86_64, mingw32             
#>  ui       RTerm                       
#>  language (EN)                        
#>  collate  Japanese_Japan.932          
#>  tz       Asia/Tokyo                  
#>  date     2017-01-15
#> Packages ------------------------------------------------------------------
#>  package   * version date       source        
#>  backports   1.0.4   2016-10-24 CRAN (R 3.3.2)
#>  devtools    1.12.0  2016-06-24 CRAN (R 3.3.2)
#>  digest      0.6.10  2016-08-02 CRAN (R 3.3.2)
#>  evaluate    0.10    2016-10-11 CRAN (R 3.3.2)
#>  htmltools   0.3.5   2016-03-21 CRAN (R 3.3.1)
#>  knitr       1.15.1  2016-11-22 CRAN (R 3.3.2)
#>  magrittr    1.5     2014-11-22 CRAN (R 3.3.1)
#>  memoise     1.0.0   2016-01-29 CRAN (R 3.3.1)
#>  R6        * 2.2.0   2016-10-05 CRAN (R 3.3.2)
#>  Rcpp        0.12.8  2016-11-17 CRAN (R 3.3.2)
#>  rmarkdown   1.2     2016-11-21 CRAN (R 3.3.2)
#>  rprojroot   1.1     2016-10-29 CRAN (R 3.3.2)
#>  stringi     1.1.2   2016-10-01 CRAN (R 3.3.2)
#>  stringr     1.1.0   2016-08-19 CRAN (R 3.3.2)
#>  withr       1.0.2   2016-06-20 CRAN (R 3.3.1)
#>  yaml        2.1.14  2016-11-12 CRAN (R 3.3.2)
```