インタフェースと型クラス、どちらでもできること・どちらかでしかできないこと

最近にわかに **_型クラス_** が盛り上がっているようです。しかし、型クラスはインタフェースに似たものだという意見もあればまったく別のものだという意見もあり、混乱する人が多いのではないかと思います。

そのような混乱を招く理由は、 **インタフェースと型クラスはどちらも抽象化を実現するためのもの** であり、

1. **インタフェースでも型クラスでもできること**
2. **インタフェースでしかできないこと**
3. **型クラスでしかできないこと**

があるからです。 1 に着目した人は似ていると語り、 2 や 3 に着目した人はまったく違うものだと言います。

本投稿では、 Java / Kotlin のインタフェース、 Haskell の型クラス、 Swift のプロトコルを比較し、上記の 3 点を整理します。 Swift のプロトコルを加えるのは、 Swift のプロトコルがインタフェースと型クラスの両方の性質を備えたものなので、比較対象としておもしろいからです。

比較対象言語に[盛り上がりの発端](http://qiita.com/kmizu/items/b656d8cf45abc442598a)となった Scala が含まれていないのは、僕が Scala に詳しくないからです。もしかしたら @kmizu さんあたりがコメントで Scala についても補足・比較してくれるかもしれません🙂

なお、本投稿では言語間の用語の差異を Java に寄せて書いてあります。同じ概念でも言語によって呼び方が違ったりしますが、すべての言語にとって正確な表現で書こうとすると文章が冗長になってしまいます。四つの言語の中では Java が最も広く知られていると思うのと、型クラスがある言語を使いこなしている人は大抵インタフェースについても知っているので、本投稿の想定読者ではないからです。

## インタフェースでも型クラスでもできること

動物を表す `Animal` インタフェースおよび型クラスを作ってみましょう。 `Animal` は「種」を表す `species` と、その個体の名前を表す `name` を持っているものとしましょう。たとえば、猫のタマであれば `species` は `"ネコ"` で、 `name` は `"タマ"` です。

```java
// Java ✅
interface Animal {
  String getSpecies(); // 種の名称
  String getName();
}
```

```kotlin
// Kotlin ✅
interface Animal {
  val species: String
  val name: String
}
```

```swift
// Swift ✅
protocol Animal {
  var species: String { get }
  var name: String { get }
}
```

```haskell
-- Haskell ✅
class Animal a where
  species :: a -> String
  name :: a -> String
```

Kotlin と Swift では `species` と `name` をメソッドではなくプロパティにしました。プロパティとは、 Java でいうフィールドのように見えるけれども、実体としてはメソッドのようなものです。 `foo.bar` と書くと `foo.getBar()` が呼ばれるようなものと思って下さい。

Haskell にはメソッドがないので代わりに関数を使います。メソッドは `animal.getName()` のような形でコールしますが、関数の場合は `animal` を引数に渡して `getName(animal)` のようにコールします。 Java で表すと次のような違いです。

```java
// Java
class Cat {
  private String name;

  // メソッド
  public String getName() {
    return this.name;
  }

  // 関数（がやっているのと同じようなこと）
  public static String getName(Animal animal) {
    return animal.name;
  }

  ...
}
```

どちらの場合でも同じようなこと[^1]が実現できるのがわかると思います。

前述の Haskell のコードで `a -> String` と書いてあるのは、引数として `a` 型の値を受け取って `String` を返すという意味です。 `Animal a` の `a` は何かというと、 `Animal` を満たす具体的な型、 `Cat` や `Dog` を表しています。つまり、 `name :: a -> String` は、 `Cat` や `Dog` を受け取ってその名前を `String` で返す関数 `name` の宣言です。

では、 `Animal` を満たす具象型 `Cat` を実装しましょう。

```java
// Java ✅
class Cat implements Animal {
  private final String name;

  Cat(String name) {
    this.name = name;
  }

  @Override
  String getSpecies() {
    return "ネコ"
  }

  @Override
  String getName() {
    return name;
  }
}
```

```kotlin
// Kotlin ✅
class Cat(override val name: String) : Animal {
  val species: String
    get() = "ネコ"
}
```

```swift
// Swift ✅
struct Cat: Animal {
  var species: String {
    return "ネコ"
  }

  let name: String
}
```

```haskell
-- Haskell ✅
data Cat = Cat String

instance Animal Cat where
  species _ = "ネコ"
  name (Cat n) = n
```

`species` は型そのものに紐付いているので（ `Cat` なら `"ネコ"` ）フィールドで保持する必要はありません。そのため、 `Cat` はただ一つの `String` 型のフィールド `name` を持ちます。同じように `Dog` 型を作ることもできます。

このように、 **`Animal` がインタフェースでも型クラスでも、 `Animal` を実装する型 `Cat` や `Dog` などが満たすべき性質を記述し、その実装を強制することができました**。

## インタフェースでしかできないこと

次は、 `Animal` を受け取って `"タマ (ネコ)"` のように、名前と種を結合した文字列を返す関数／メソッド `getDisplayName` / `displayName` を作ってみましょう。

```java
// Java ✅
static String getDisplayName(Animal animal) {
  return animal.getName() + " (" + animal.getSpecies() + ")";
}
```

```kotlin
// Kotlin ✅
fun displayName(animal: Animal): String {
  return "${animal.name} (${animal.species})"
}
```

```swift
// Swift ✅
func displayName(animal: Animal) -> String {
  return "\(animal.name) (\(animal.species))"
}
```

```haskell
-- Haskell ⛔
-- できない
```

**これは型クラスではできません。インタフェースは型ですが、型クラスは型ではありません。そのため、抽象的な `Animal` 型というものは存在しません。当然、 `Animal` 型の値を引数として受け取るようなこともできません。**

## インタフェースでも型クラスでもできること (2)

Java の感覚では、 `Animal` を型として使えないと困るように思います。しかし、 `Animal` 型がなくてもこれを解決する方法があります。ジェネリックメソッド／関数です（ Haskell では **_パラメータ多相（ Parametric polymorphism ）_** と呼びます）。

`getDisplayName` はジェネリクスを使って次のように実装することもできます。

```java
// Java ✅
static <A extends Animal> String getDisplayName(A animal) {
  return animal.getName() + " (" + animal.getSpecies() + ")";
}
```

```kotlin
// Kotlin ✅
fun <A : Animal> displayName(animal: A): String {
  return "${animal.name} (${animal.species})"
}
```

```swift
// Swift ✅
func displayName<A: Animal>(animal: A) -> String {
  return "\(animal.name) (\(animal.species))"
}
```

```haskell
-- Haskell ✅
displayName :: (Animal a) => a -> String
displayName a = name a ++ "(" ++ species a ++ ")"
```

`getDisplayName` をこのように実装すれば、 `Animal` 自体を型として使わなくても `getDisplayName` を抽象的に（ `Cat` や `Dog` それぞれに個別に実装するのではなく、まとめて）実装することができました。これを使うコードは次のようになります。

```java
// Java
getDiplayName(new Cat("タマ")); // タマ (ネコ)
getDiplayName(new Dog("ポチ")); // ポチ (イヌ)
```

さっきの `static String getDisplayName(Animal animal)` の場合と同じように動作していますね。 **`Animal` が型クラスの場合、 `Animal` 型自体は存在しません。しかし、それでもジェネリクス（パラメータ多相）を使うことでインタフェースと似たような抽象化を実現できました。**

### アドホック多相

Haskell で `name` や `species` が、 `Cat` に対して呼ばれた場合と `Dog` に対して呼ばれた場合でどの実装が呼ばれるか切り替わる仕組みを **_アドホック多相（ Ad hoc polymorphism ）_** と言います。

```haskell
-- Haskell
species (Cat "タマ") -- "ネコ"
species (Dog "ポチ") -- "イヌ"
```

Java の視点でみるとただのオーバーロードに見えるかもしれません。

```java
// Java
static String getSpecies(Cat cat) {
  return "ネコ";
}

static String getSpecies(Dog dog) {
  return "イヌ";
}

getSpecies(new Cat("タマ")); // "ネコ"
getSpecies(new Dog("イヌ")); // "イヌ"
```

しかし、これをジェネリクス（パラメータ多相）と組み合わせてみるとどうでしょう。 Java では Haskell と同じことができません。

```java
// Java
static <A extends Animal> String getDisplayName(A animal) {
  return getName(animal) + " (" + getSpecies(animal) + ")"; // コンパイルエラー
}
```

一方で、オブジェクト指向言語におけるポリモーフィズム（ **_Subtype polymorphism_** と呼ばれることもある）のようにも見えるかもしれません。しかし、アドホック多相では抽象的な型 `Animal` を介して `name` や `species` が呼ばれているわけでもありません。↓のコードはポリモーフィズムではなくオーバーロードのように見えると思います。

> ```haskell
-- Haskell
species (Cat "タマ") -- "ネコ"
species (Dog "ポチ") -- "イヌ"
```

`displayName` の例のようにパラメータ多相とアドホック多相を組み合わせると一気にオブジェクト指向のポリモーフィズムのように見えると思います。

> ```haskell
-- Haskell ✅
displayName :: (Animal a) => a -> String
displayName a = name a ++ "(" ++ species a ++ ")"
```

しかし、このような場合でも `a` は常に具体的な型（ `Cat` や `Dog` など）を指し、抽象的な `Animal` 型の値に対して `name` や `species` が呼ばれているわけではありません。アドホック多相はアドホック多相であり、オブジェクト指向のポリモーフィズムとはまた別のポリモーフィズムです。

なお、 Swift のプロトコルはインタフェースのように使えると書きましたが、実はそのような使い方をすることはそれほど多くありません。標準ライブラリもパラメータ多相とアドホック多相を組み合わせた方法で実装されていることが多いです。

## インタフェースでしかできないこと (2)

↑の方法も万能ではありません。

例として、 `List<Animal>` を受け取ってそれら動物の名前のリスト `List<String>` に変換する関数／メソッド `getNames` / `names` を考えてみましょう。先程と同じようにジェネリクス（パラメータ多相）で実装してみます。

```java
// Java ✅
static <A extends Animal> List<String> getNames(List<A> animals) {
  return animals.stream().map(x -> x.getName());
}
```

```kotlin
// Kotlin ✅
fun <A : Animal> names(animals: List<A>): List<String> {
  return animals.map { it.name }
}
```

```swift
// Swift ✅
func names<A: Animal>(of animals: [A]) -> [String] {
  return animals.map { $0.name }
}
```

```haskell
-- Haskell 🤔
names :: (Animal a) => [a] -> [String]
names animals = map name animals
```

一見どれでもうまく実装できたように見えます。しかし、↑のコードで Haskell 以外ではできて Haskell ではできないことがあります。それは、↓のように `Cat` や `Dog` など、異なる具象型のインスタンスが混ざった `animals` を渡すことです。

```java
// Java ✅
getNames(Arrays.asList(new Cat("タマ"), new Dog("ポチ")));
```

```kotlin
// Kotlin ✅
names(listOf(Cat("タマ"), Dog("ポチ")))
```

```swift
// Swift ✅
names(of: [Cat("タマ"), Dog("ポチ")])
```

```haskell
-- Haskell ⛔
-- できない
names [Cat "タマ", Dog "ポチ"] -- コンパイルエラー
```

Haskell では `Animal` は型クラスであって型ではないので、いくらジェネリクス（パラメータ多相）を使って引数を受けるようにしたところで `List<Animal>` 相当の型が作れるわけではありません。 **あくまで `List<Cat>` も `List<Dog>` もどちらでも受け取れる関数が作れるだけです。抽象的な `Animal` のリストを受け取れるわけではないのです。**

**（追記）** @cohei@github さんに[コメントいただいた](http://qiita.com/koher/items/ee31222b7f9b0ead3de7#comment-0bbfa996d07e27d48103)ように Haskell でも Existential を使えば `Animal` のリストのようなことができます。実は、 Swift でも `Animal` 型の変数に `Cat` や `Dog` を代入した場合には暗黙的に Existential に変換されています。そうでないとメモリレイアウトが異なる（今はたまたま同じですが）値型の `Cat` や `Dog` に対して抽象的な `Animal` 型などというものを考えることはできません。そういう意味でも Swift でプロトコル型変数を使ってサブタイピングするのはちょっと特殊で、 Swift のプロトコルは型クラス的です。

## 型クラスでしかできないこと

次は逆に、型クラスならできるけどインタフェースではできないことを見てみましょう。

Java や Kotlin では `equals` / `==` を使ってインスタンスが同値であるかを判定します。 `equals` や `==` はルートクラス（ Java では `Object`、 Kotlin では `Any` ）で定義されているため、どんなクラスのインスタンスでも比較をすることが可能です。

`equals` を実装するときは↓のような感じです。

```java
// Java
class Cat implements Animal {
  ...

  @Override
  boolean equals(Object object) {
    if (!(object instanceof Cat)) {
      return false;
    }

    Cat cat = (Cat)object;
    return getName().equals(cat.getName());
  }
}
```

`equals` の最初の行で、渡されたオブジェクトが `Cat` のインスタンスかどうかを判定しています。しかし、本当に `Cat` 以外のあらゆる型のインスタンスとの同値性をチェックしたいでしょうか。 `Cat` 同士の比較さえできればよいのであれば、↓のようにシンプルに書けます。

```java
// Java
class Cat implements Animal {
  ...

  boolean equals(Cat cat) {
    return getName().equals(cat.getName());
  }
}
```

しかし、このような `equals` を継承やインタフェースによって強制することはできません。試しに、そのような制約を表すインタフェース `Equatable` を考えてみましょう。

```java
// Java
interface Equatable {
  boolean equals(Equatable object);
}
```

一見これでよさそうに見えるかもしれませんが、これではダメです。 `Cat` に `Equatable` を実装させると次のようになります。

```java
// Java
class Cat implements Animal, Equatable {
  ...

  @Override
  boolean equals(Equatable object) {
    if (!(object instanceof Cat)) {
      return false;
    }

    Cat cat = (Cat)object;
    return getName().equals(cat.getName());
  }
}
```

`equals` の引数の型が `Object` から `Equatable` に変わっただけです。引数の型を `Cat` にできるわけではありません。

次のようにしたらどうでしょうか？

```java
// Java
interface Equatable<T> {
  boolean equals(T object);
}

class Cat implements Animal, Equatable<Cat> {
  ...

  @Override
  boolean equals(Cat cat) {
    return getName().equals(cat.getName());
  }
}
```

`equals` の引数の型を `Cat` にすることができました。しかし、これは `class Cat implements ..., Equatable<Cat>` としたからです。もし `class Cat implements ..., Equatable<String>` としたら `equals` の引数の型は `String` になってしまいます。 `A implements Equatable<A>` の二つの `A` を必ずそろえて使うことを強制することはできません。

Haskell や Swift などの言語ではそのような制約を記述することができます。

```java
// Java ⛔
// できない
```

```kotlin
// Kotlin ⛔
// できない
```

```swift
// Swift ✅
protocol Equatable {
  static func ==(lhs: Self, rhs: Self) -> Bool
}
```

```haskell
-- Haskell ✅
-- ↓の `Eq` は Swift における `Equatable` 相当のもの
class  Eq a  where
  (==) :: a -> a -> Bool
```

Swift のコードでは `Self` というキーワードが出てきています。これは自分自身の型を表します。たとえば、 `Cat` を `Equatable` にするなら `==` の引数は `Cat` に、 `String` を `Equatable` にするなら `==` の引数は `String` になります。

```swift
// Swift
struct Cat: Equatable {
  static func ==(lhs: Cat, rhs: Cat) -> Bool {
    return lhs.name == rhs.name
  }
}
```

`==` の引数の型が `Self` ではなく `Cat` になっていることに注意して下さい。 `Self` が意味するのは、そのプロトコルを実装する型自身です。

Haskell のコードもそれと同じことを意味します。 `==` は二つの `a` 型の引数をとり `Bool` を返します。この `a` には `Cat` や `String` など具体的な型が入るので、 `Cat` に `==` を使うと `Cat` 同士を、 `String` に `==` を使うと `String` 同士を比較することになります。

Swift ではプロトコルをインタフェースのように使い、抽象的なプロトコル型の変数を作ることができました。これを `Equatable` でやってみるとどうなるでしょうか。

```swift
// Swift
let equatable: Equatable = Cat(name: "タマ") // コンパイルエラー
```

コンパイルエラーになりました。なぜでしょう？

`Cat` の `==` は `Cat` に対してしか使えません。同じように、 `String` の　`==` は `String` にしか使えません。

```swift
// Swift
Cat(name: "タマ") == Cat(name: "タマ") // OK
"abc" == "abc" // OK
```

もし `Equatable` 型の変数が作れるとして、その `==` は何型と何型を比較するのでしょう？

```swift
// Swift
let equatable: Equatable = Cat(name: "タマ") // コンパイルエラー
equatable == "abc" // `Cat` と `String` を比較する `==` などない
```

↑のように、 `Cat` と `String` を比較する `==` はどこにも実装されていません。そのため、そもそも `Equatable` 型の変数を作れないようになっているのです。 `Self` を導入することで、オブジェクト指向のサブタイピングによるポリモーフィズムは不可能になります。

**このように、型クラスを使えばインタフェースとは違い、 `Self` のようなより柔軟な制約を記述することができます。しかし、それが実現できるということはインタフェースと違ってサブタイピングによるポリモーフィズムができないことを意味します。**

Swift のプロトコルは `Self` を使わないなどサブタイピングを許容できる場合はインタフェースのように型として使えますが、 `Self` が記述されたプロトコルは型として使うことができません。型クラスとなり、型ではなくなります[^2]。

## 型クラスでしかできないこと (2)

型クラスではさらに強力な制約を書くことができます。

例として、 `map` を抽象化することを考えてみましょう。 Java では `Stream` も `Optional` も `map` メソッドを持っています[^3]。

```java
// Java
interface Stream<T> {
  <R> Stream<R> map(Function<T, R> mapper);
  ...
}

class Optional<T> {
  <R> Optional<R> map(Function<T, R> mapper) { ... }
  ...
}
```

どちらも同じようなシグネチャです。似たようなものは抽象化することで実装の重複を避けることができます。この `map` も抽象化できるとうれしいはずです。

`map` を抽象化するということは、抽象的に `map` が何をやっているのかを説明できなければなりません。 `Stream` も `Optional` も内部に `T` 型の値を保持しています。 `map` は `mapper` を使ってその値を `T` 型から `R` 型に変換します。そしてその変換結果を `Stream` / `Optional` で包み直して返します。これが `map` の挙動です。そのような `map` を持つものを `Functor` と呼ぶことにしましょう。

さて、ここでポイントなのは、 `Stream` の `map` は変換後の値を `Stream` で包み、 `Optional` の `map` は変換後の値を `Optional` で包んで返すという点です。 `Stream<T>` と `Stream<R>` は異なる型なので、（ Swift で言うところの） `Self` で表すこともできません。

残念ながら Swift には（ Swift 3.1 時点では） `Self` 以上の表現力がないので、そのような制約を記述することはできません。 [Swift Evolution](https://github.com/apple/swift-evolution) [^4] では何度か話題に挙がっていますが、他にやるべきことがたくさんあり、将来的に導入されることはあり得るが現時点の優先度は低いと判断されています。

```java
// Java ⛔
// できない
```

```kotlin
// Kotlin ⛔
// できない
```

```swift
// Swift ⛔
// できない
```

```haskell
-- Haskell ✅
-- ↓の `fmap` は Java の `map` と同じ
class  Functor f  where
    fmap :: (a -> b) -> f a -> f b
```

当然、型クラス `Functor` を抽象的な `Functor` 型として扱うことはできません。しかし、パラメータ多相とアドホック多相を使えば、 `Functor` を満たす型に対して抽象的に処理を実装することができます。

たとえば、 `Functor` の中身の値が数値だった場合に、その中身を二乗する関数 `square` を実装してみましょう。

```haskell
-- Haskell
square :: (Functor f, Num a) => f a -> f a
square = fmap (\x -> x * x)
```

そうすれば、リストも `Maybe` （ Java や Swift の `Optional` の相当）も `fmap` を持つ `Functor` なので、 `square` はリストに対しても `Maybe` に対しても使うことができます。

```haskell
-- Haskell
square [2, 3, 5]  -- [4, 9, 25]
square (Just 3)   -- Just 9
```

`Just 3` は Java で言えば `Optional.of(3)` の意味です。

このように、型クラス `Functor` を使って抽象的に `map` を利用する `square` を実装することができました。この表現力はインタフェースにはないものです。

## まとめ

- インタフェースと型クラスはどちらも抽象化を実現するためのもので、型が満たすべき性質を記述し、それを実装する型に強制することができる
- インタフェースはそれ自体が型になることができ、サブタイピングによる抽象化が実現できる
- 型クラスはそれ自体が型になることはできないが、より柔軟な抽象化が実現できる

---

[^1]: 継承してオーバーライドするなどすれば挙動が異なりますが、それはここで説明したいことの主旨とは関係がありません。

[^2]: Swift の用語ではそれでも型かもしれませんが、ここで言いたいのは変数等の型として利用することができなくなるということです。

[^3]: 見やすいようにワイルドカードを取り除いています。

[^4]: 次のバージョンの Swift の言語仕様を話し合うオフィシャルな場所。