「プロトコル指向プログラミングについて調べてみた」をScalaでやってみた

# 「プロトコル指向プログラミングについて調べてみた」をScalaでやってみた
　[ドワンゴのscala_text](http://dwango.github.io/scala_text)をもう少しで読み切るので、Scalaの練習用のために
[「プロトコル指向プログラミングについて調べてみた」](http://qiita.com/kotaro_p/items/4a4ebd34b15ccbcd1895)をScalaでやってみました。

+ この記事でわかること
    - `implicit class`による、ある程度型安全な、既存の型へのメソッド定義追加…の方法
    - コーディング上での上記の利点


# Bad Case
　元記事の「実際にやってみた」の章の前半、良くないケースの例。

```scala:Person.scala
package persons

trait Person {
    var name: String
    var age: Int
}
```

```scala:Engineer.scala
package persons

class Engineer extends Person {
    var name: String = "boku"
    var age: Int     = 22
    def bress(): Unit = println("すーはーすーはー")
}
```

```scala:Idol.scala
package persons

class Idol extends Person {
    var name: String = "Chihaya"
    var age: Int     = 15
    def bress(): Unit = println("すーはーすーはー")
}
```

本家にはありませんが、Mainも。

```scala:Main.scala
import persons._

object Main {
    def main(args: Array[String]): Unit = {
        val x = new Engineer
        x.bress
        val y = new Idol
        y.bress
    }
}
```

```output:output
すーはーすーはー
すーはーすーはー
```


## 余談 - Scalaの無引数メソッドのbracketの有無について
　Scalaで無引数メソッドに()を書くかどうかは、純粋関数であるかどうかで決まるしきたりだそうです。

+ メソッドが副作用を持たない (標準入出力(及び標準エラー出力)を伴わず、インスタンスの状態を変更も変更しない)
    - ()をつけない
+ メソッドが副作用を持つ
    - ()をつける


# Better Case
　というわけで戻って、愚直に元記事にある、良いケースを。

```scala:Person.scala
package persons

trait Person {
    var name: String
    var age: Int
    def bress(): Unit = println("すーはーすーはー")
}
```

```scala:Engineer.scala
package persons

class Engineer extends Person {
    var name: String = "boku"
    var age: Int     = 22
}
```

```scala:Idol.scala
package persons

class Idol extends Person {
    var name: String = "Chihaya"
    var age: Int     = 15
}
```

　Scalaは問題のある菱形継承も検知してくれるし、overrideの必要がある場合はコンパイル時に`override`キーワードを要請してくれるのでこれでもいいでしょう :)

ただし、本家の場合`extension`を定義することで、
(後から定義を追加できるという意味で)ボトムアップなコーディングを可能にする…というのが利点と言っているはず。
(だよね？ :D)


# Best Case
　なので`implicit class`を使って型安全な追加定義を行います。  
ここでの「型安全」は、「別の型で対象の型のためのメソッドを定義できる、対象の型の定義は変更しないでいい」という意味で用いてます :)


```scala:Person.scala
package persons

trait Person {
    var name: String
    var age: Int
    //def bress(): Unit = println("すーはーすーはー")
}
```

```scala:Engineer.scala
package persons

class Engineer extends Person {
    var name: String = "boku"
    var age: Int     = 22
}
```

```scala:Idol.scala
package persons

class Idol extends Person {
    var name: String = "Chihaya"
    var age: Int     = 15
}
```

ここに`implicit class`を追加。

```scala:PersonExtension.scala
package persons

object PersonExtension {
    implicit class PersonExt(val x: Person) {
        def bress: Unit = println("すーはーすーはー")
    }
}
```

Mainでこれを`import`して

```scala:Main.scala
import persons._
import persons.PersonExtension._  // !

object Main {
    def main(args: Array[String]): Unit = {
        val x = new Engineer
        x.bress
        val y = new Idol
        y.bress
    }
}
```

```output:output
すーはーすーはー
すーはーすーはー
```

よっしゃ！


# ここから余談

## ある対象の型に対する追加定義でボトムアップなコーディングを実現する…ということ
　これはとってもベンリですね。  
上記の例で言うと、「後から`bress()`が必要になった」という事象に対しても柔軟に対応ができます。

従来は「Personの定義に`bress()`を追加する」という対応が必要でしょうから… :(  
Java7以下とかだと

1. `interface Person`に`bress()`の宣言を追加
2. ***n個の***Person実装クラスに`bress()`の定義を追加

とか悲惨になりますもんね…。

あっ、えっと、つまりコーディングが楽になるんです！！


## Swiftのextensionと同様の、他言語でのアプローチ
- C#: `static class`のstaticメソッド
- Scala: `implicit class`
- Haskell: `class`(型クラス)と`instance`