R言語S3クラスの実装

# 概要
他の言語と比べるとRの(S3)クラス定義は特殊です（※個人の感想）。
これはR言語は**統計処理言語**なのが意識されて作られていることに由来しているからでしょう。

ただ、慣れるとオブジェクト指向っぽい書き方ができる気がする（完全にできるとは言ってはいない
今回のクラス定義はS3クラスについて雑にまとめました（他にはS4,R5,R6等々いろいろある）

### 参考出典
基本的に下記のリンクを参考にしてます

 - https://www.cyclismo.org/tutorial/R/s3Classes.html
 - http://adv-r.had.co.nz/S3.html
 - http://rtokei.tech/memo/rのことを学ぶ010s3クラス/

### 注意
忘備録的に書いているので、分かりにくいです。また、ソフトウェア工学しっかりとは学んでいないので、内容は保証しません。

# クラス定義
RのS3クラス定義は簡単

```R
x <- 1
class(x) <- "foo"
class(x)
```
これで、変数`x`は`foo`クラスとして定義される。正直、なんじゃこりゃ。

# 総称関数

なんとなくの理解で総称関数を語る（＝合っているとは保証しない）。詳しくは下記参照。

 - http://sumim.no-ip.com/wiki/608
 - http://rtokei.tech/memo/rのことを学ぶ010s3クラス/

R言語で分析すると何気なく使っている`print`関数。
文字列だろうが、`data.frame`クラスだろうが、`lm`関数の結果(`lm`クラス)だろうが、関係なく`print`してくれる。このように入力されるデータのクラスに関わらず、なんらかの出力を出してくれる便利な関数が「総称関数」です。

```R
print("Hi")
print(iris)
print( lm(Sepal.Length~Petal.Length,iris) )
```

よって、上記は下記と一緒の出力結果を得る

```R
print.default("Hi")
print.data.frame(iris)
# print.lm ( lm(Sepal.Length~Petal.Length,iris) )
```

つまり、Rの処理としては以下のことが行われている
![スライド1.png](https://qiita-image-store.s3.amazonaws.com/0/235984/84c86a1d-fb97-3abf-c016-b230a70f7217.png)

新しい総称関数を作りたい場合は、以下のように`UseMethod`関数を使う。

```R
UseMethod("GetFirst")
```

# クラスの継承
RのS3クラス継承は少し分かりにくい。

```R
class(x) <- c("hoo","foo")
```

これで、xは`hoo`と`foo`クラスを持つ。上の場合だと`foo`クラスが親で、`hoo`クラスは子クラスとなる。つまり、要素番号が一番若いクラスが子クラスになる。実際に以下のスクリプトで確認できる。

```R
 x <- list(x = 1,
           y = "hi")
 class(x)<-c("foo","hoo")
 greeting <- function(x){
   UseMethod("greeting",x)  
 }
 greeting.foo <- function(x){
   print(x$y)
 }
 greeting.hoo <- function(x){
   print(x$x)
 }
greeting(x)
> [1] "hi"
```

上では`greeting`関数を総称関数にして、変数`x`に`foo`クラスと`hoo`クラスを持たせた。それぞれのクラスについて関数を定義した結果、`foo`クラスの結果が返されている。

```R
 x <- list(x = 1,
           y = "hi")
 class(x)<-c("foo","hoo")
 greeting <- function(x){
   UseMethod("greeting",x)  
 }
 greeting.hoo <- function(x){
   print(x$x)
 }
 greeting(x)
> [1] 1

```

二つ目は`foo`クラスに`greeting`関数について何も定義していないと、親である`hoo`クラスの結果を返している。


# クラス実装

もう少しオブジェクト指向っぽい実装を行いたい場合は以下のように実装する。

```R
NorthAmerican <- function(eatsBreakfast=TRUE,myFavorite="cereal")
{

        me <- list(
                hasBreakfast = eatsBreakfast,
                favoriteBreakfast = myFavorite
       )

        ## Set the name for the class
        class(me) <- append(class(me),"NorthAmerican")
        return(me)
}
```

`list`の部分をフィールドとして定義。
`class(me) <- append(class(me),"NorthAmerican")`で継承関係を定義する。
以下のように、インスタンス生成っぽいアトモスフィア（雰囲気）が出てくる。

```R
taro <- NorthAmerican(eatsBreakfast=TRUE,myFavorite="rice")
```

クラスにメソッドを追加するときは関数を総称関数にして、自ら定義したクラスの関数を記述する。

```R
setHasBreakfast <- function(elObjeto, newValue)
        {
                print("Calling the base setHasBreakfast function")
                UseMethod("setHasBreakfast",elObjeto)
                print("Note this is not executed!")
        }

setHasBreakfast.default <- function(elObjeto, newValue)
        {
                print("You screwed up. I do not know how to handle this object.")
                return(elObjeto)
        }


setHasBreakfast.NorthAmerican <- function(elObjeto, newValue)
        {
                print("In setHasBreakfast.NorthAmerican and setting the value")
                elObjeto$hasBreakfast <- newValue
                return(elObjeto)
        }
```

[参考にしたサイト](https://www.cyclismo.org/tutorial/R/s3Classes.html)では上記の実装になっていたが、以下のような書き方でも可能

```R
setHasBreakfast <- function(object , newValue)
        {
                print("Calling the base setHasBreakfast function")
                UseMethod("setHasBreakfast")
                print("Note this is not executed!")
        }
```

`magrittr`パッケージを使うと、メソッドの書き方が他の言語と見慣れた感じになる。

```R
taro <- NorthAmerican(eatsBreakfast=TRUE,myFavorite="rice")

setHasBreakfast <- function(object, newValue)
{
  print("Calling the base setHasBreakfast function")
  UseMethod("setHasBreakfast")
  print("Note this is not executed!")
}

setHasBreakfast.default <- function(object,newValue)
{
  print("You screwed up. I do not know how to handle this object.")
  return(object)
}


setHasBreakfast.NorthAmerican <- function(object,newValue)
{
  print("In setHasBreakfast.NorthAmerican and setting the value")
  object$hasBreakfast <- newValue
  return(object)
}
 
require(magrittr)

taro %>% setHasBreakfast( newValue = FALSE)
```

詳しい説明は[参考にしたサイト](https://www.cyclismo.org/tutorial/R/s3Classes.html)に譲るが、下記のようにメソッドを実装する方法もある。

```R
bubba <- NorthAmericain(myFavorite="oatmeal")
bubba$getFavoriteBreakfast()
[1]"oatmeal"
```