Dart 継承を理解してみる


Dartの継承はそんなにむずくない。怖くないはず。まだ良くわかってないから1個ずつ理解するためにまとめる。

## 仕様的なはなし
* ~~多段継承~~ 多重継承しないはず
	* 追記)多段継承は普通にできます
* ``interface``宣言は無い。``class``宣言が暗黙的に``interface``になる的なやつ
	* ``interface``したけりゃ実装無しの``abstract``にすればいいはず
* ``Generics``が使える
* ``extends``と``implements``がある

## Basic extends

```dart:main.dart
class Parent {
  String getName() {
    return 'parent';
  }
}

class Child extends Parent {
  String getName() {
    return "child [Not ${super.getName()}]";
  }
}

main(){
  print(new Child().getName());
  //> child [Not parent]
}
```

## Private property

dartの``private``/``public``は名前の先頭に ``_`` があるかどうかで決まる。
``protected``は無いって噂だしきっと親のprivateプロパティにはアクセスできないじゃないかな。

```dart:main.dart
class Parent {
  String _name = 'parent';
  String getName() {
    return this._name;
  }
}

class Child extends Parent {
  String getName1() {
    return "child [Not ${super.getName()}]";
  }
  String getName2() {
    return "child [Not ${super._name}}";
  }
}

main(){
  Child child = new Child();
  print(child.getName1());
  print(child.getName2());
  print(child._name);
  //> child [Not parent]
  //> child [Not parent}
  //> parent
}
```

あれ、アクセスできた。なんでやねん。
libraryが一緒だとアクセスできちゃうらしい。なるほど。

```dart:main.dart
import './child.dart';

main(){
  Child child = new Child();
  print(child.getName1());
  //> child [Not parent]
  print(child.getName2());
  //> Unhandled exception: Class 'Child' has no instance getter '_name'.
  print(child._name);
  //> Unhandled exception: Class 'Child' has no instance getter '_name'.
}
```

```dart:parent.dart
class Parent {
  String _name = 'parent';
  String getName() {
    return this._name;
  }
}
```

```dart:child.dart
import './parent.dart';

class Child extends Parent {
  String getName1() {
    return "child [Not ${super.getName()}]";
  }
  String getName2() {
    return "child [Not ${super._name}}";
  }
}
```
ちゃんとエラーでてくれる。すばら。
というか library を明示的にかかなけりゃ別library的な扱いになるのかねぇ。ファイル分割しただけなんだけど。

## implements

```dart:main.dart
class Parent {
  String getName() {
    return 'parent';
  }
}

class Child implements Parent {
  String getName() {
    return "child [Not ${super.getName()}]";
  }
}

main(){
  print(new Child().getName());
  //> Unhandled exception: Super class of class 'Child' has no instance method 'getName'.
}
```

うん。super使えないね。

## implements errors

implementsってくらいだから実装なかったら死ぬはず。

```dart:main.dart
class Parent {
  String getName();
}

class Child implements Parent {
}

main(){
  print(new Child());
  //> Instance of 'Child'
}
```

あれ、getNameの実装をChildに求めたはずなのに特に怒られない。
``abstract class Parent``とかしても関係ない。
あるぇー？

```sh
$ dartanalyzer main.dart
Analyzing [main.dart]...
[warning] Missing concrete implementation of 'Parent.getName' (/path/to/main.dart, line 5, col 7)
1 warning found.
```

なるほど。dartanalyzerだとエラーになるけど、コンパイル時にはエラーにならないのか。
この辺も``Optional Types``の方針なのかな。

という事は、CIで``dartanalyzer``回すようにしないといけないだろうね。
IDEでは一応エラーになってたから、開発中に全く気づけ無いという事はなさそう。

![sandbox_main.dart_-__dartBBS__-_dartBBS_-____IdeaProjects_dartBBS_-3.png](https://qiita-image-store.s3.amazonaws.com/0/3865/47396b81-f808-1f2f-9ed1-78e51a98114a.png "sandbox_main.dart_-__dartBBS__-_dartBBS_-____IdeaProjects_dartBBS_-3.png")

## generics

```dart:main.dart
import 'dart:mirrors';

abstract class Family {
  String getName();
  String getFamilyName() {
    return 'yamada';
  }
}
class Child extends Family {
  String getName() {
    return 'taro';
  }
}
class Parent extends Family {
  String getName() {
    return 'hanako';
  }
}
class Member<T extends Family> {
  String getFullName(){
    ClassMirror cm = reflectClass(T);
    T t = cm.newInstance(const Symbol(''), []).reflectee;
    return "${t.getName()} ${t.getFamilyName()}";
  }
}
main() {
  print(new Member<Child>().getFullName());
  //> taro yamada
  print(new Member<Parent>().getFullName());
  //> hanako yamada
}
```

使い方として合ってるかしらんけど、こんな感じの事ができるらしい。
``generics``を``extends``周りで使う意味とかやり方とかを理解してない。
でも``reflect``が出てきてる時点であんま良くない気がする。

``Family``を``extends``した``Parent``と``Child``がいて、それらを受け取る？事ができる``Member<T extends Family>``がいて、``Member``の中からは``T``が``Parent``だったり``Child``だったりするので、``reflect``でインスタンス取得してアレコレする的な？

## with (mix-in)

```dart:main.dart
class Family {
  String getFamilyName() {
    return 'yamada';
  }
}
class Parent {
  String getName() {
    return 'taro';
  }
}
class Child extends Parent with Family {
  String getName() {
    return '${super.getName()} ${super.getFamilyName()}';
  }
}
main() {
  print(new Child().getName());
  //> taro yamada
}
```

``with``でMix-inできるみたい。でも``extends``は必ず必要。
``extends``いらないような場合は``Object``を``extends``すればいいらしい。

```dart:main.dart
class Family {
  String getFamilyName() {
    return 'yamada';
  }
}
class Child with Family {
  String getName() {
    return '${super.getFamilyName()}';
  }
}
main() {
  print(new Child().getName());
}

//>[error] The with clause cannot be used without an extends clause
```

ちょく``with``はエラーだけど、

```dart:main.dart
class Family {
  String getFamilyName() {
    return 'yamada';
  }
}
class Child extends Object with Family {
  String getName() {
    return '${super.getFamilyName()}';
  }
}
main() {
  print(new Child().getName());
  //> yamada
}
```

``extends Object``する事で動作を変えずに継承無しのMix-inができる。Good。

# まとめ

* 何か想像と挙動違うとこある
* Genericsがよくわからない
* 思ったよりむずかった
* まだ理解が足りないので追加で勉強だなー