Nimのオブジェクト指向の整理その２

## はじめに
[前回](https://qiita.com/souchan-t/items/778bac39cf8f4c212ed6)、から随分時間がたってしまったが、積み残していた「継承」などを中心に。Javaと比較しつつ。
nimのバージョンは以下の通り。

```bash
$nim -v #=>0.19.0
```

## まとめ ##
- 継承は多重継承できない
- 親メソッド呼びは、ちょっと独特
- インターフェイス型がない


### JavaとNimの比較

<table>
<tr><th>比較項目</th><th nowrap>Java</th><th nowrap>Nim</th></tr>
<tr>
<td>継承</td>
<td nowrap><b>class</b> Child <b>extends</b> Base{</td>
<td nowarp><b>type</b> Child = <b>ref object of</b> Base</td>
</tr>
<tr>
<td>キャスト（型変換)</td>
<td nowrap>Base b = (Base) child;</td>
<td><b>var</b> b:Base = Base(child)</td>
</tr>
<tr>
<td>動的ディスパッチ・オーバライド</td>
<td><b>@Override</b><br><b>public void</b> hoge(){...}</td>
<td><b>method</b> hoge(self:Child)</td>
</tr>
<tr>
<td>親メソッド呼び</td>
<td><b>super.</b>hoge();</td>
<td>procCall Base(self).hoge()</td>
</tr>
<tr>
<td>インターフェイス型</td>
<td><b>interface</b> IHogeable{<br><b>void</b> hoge()<br>}</td>
<td>ない・・・と思う。<br>クロージャで、<B>っぽい事</B>はできる</td>
</tr>
</table>

</table>

## Nimにおける継承
NimはJavaなどに比べて、「継承」機能はあまり充実していない。公式でも「”is a”より”has a”の方がいい場合が多いよね」みたいなスタンスの模様。ただ、必要十分な機能は備えているかなと思う。

### 基本
Nimでの継承の基本は

- 親クラスは`RootObj`を継承しておく。（でないとサブクラスを作れない[^1]）
- 子クラスは`of`で継承元を指定する

[^1]: または`final`プラグマを付けても継承できない。反対に`RootObj`継承していなくても`inheritable`プラグマ付けると継承できる。


```nim
type
  Person = object of RootObj #Javaの`Object`相当である、RootObjを継承しておく
    name:string
    age:int
proc hello(p:Person)=
  echo fmt"I am {p.name}. I am Person!"
proc howOld(p:Person)=
  echo fmt"I am {p.age} years old."

type
  Student = object of Person #Personを継承
    grade:int
proc hello(s:Student)=
  echo fmt" am {s.name}. I am {$s.grade} grade Student!"

let p = Person(name:"Bob",age:20)
let s = Student(name:"Julia",age:18,grade:4)

p.hello #=> 親のhelloプロシージャ 
s.hello #=> 子のhelloプロシージャ
s.howOld #=> 子に定義はない。親のhowOldプロシージャが呼ばれる
```
ここまでは、いたって想定通りの挙動。

### キャスト（型変換）
型変換は`型名(変数)`で行うが、以下の2行目はエラーになる。

```nim
Person(s).hello #=>親のプロシージャがちゃんとよべる
var p2:Person = Person(s) #=> 実行時エラー！！
```
これは、`Person`も`Student`も**値型**のため代入時のコピーでエラーになっている模様。型定義で**参照型**にしてやればよい。（というような事があるので、原則的にobjectタイプは参照型で定義するのがよいと思われる。）

```nim
type
  Person = ref object of RootObj
    name:string
    age:int
  Student = ref object of Person
    grade:int
```

### 動的ディスパッチ（メソッドのオーバーライド）
プロシージャのオーバーライドは、C++の`virtual`みたいに（C++に明るくないけど）明示的にする必要がある。明示の仕方は`proc`を`method`にすればよい。この時、ベースのメソッドには`{.base.}`プラグマを付けろとウォーニングが出るのでつけておく。

```nim
type
 Person = ref object of RootObj
 Student = ref object of Person

method hello(self:Person){.base.} =
  echo "Person"
method hello(self:Student)=
  echo "Student"

var persons:array[2,Person] = [new Person,new Student]
for p in persons:
  p.hello
#=> Person
#=> Student
```

では、やっぱり親のメソッドを呼び出したい時はどうするのというと（Javaでいう`super.hello();`みたいなの）、ちょっと冗長だけれど`procCall`と型変換で実行できる。

```nim
method hello(self:Student)=
  Person(self).hello # ダメ。オーバライドしているのが呼び出される（この例だと無限ループでスタックオーバーフローする）
  procCall Person(self).hello # procCallをつけて呼ぶと、superみたいな挙動する。
```

### インターフェイス型
Javaでいう`interface`相当のものはない。Javaの`interface`の役割は

- 多態性としてinterface型に変換できる
- interfaceで定義されたメソッドの実装を強要できる

ことかなと思うけれど、これを実現するのは、ちと難しそう。代わりに以下のようにクロージャを利用すれば、似たような事もできなくはないけれど…冗長だな。何か他にいい案ないものか。

```java:Javaだったらこう書くけれど・・・
interface Soundable{
  public String sound();
}
class Duck implements Soundable{
  public String sound(){
    return "quack";
  }
}
class Dog implements Soundable{
  public String sound(){
    return "bow!!";
  }
}
class Test{
  public static void main(String[] args){
    Duck duck = new Duck();
    Dog  dog  = new Dog();
    Soundable[] animals = {duck, dog};

    for (Soundable animal:animals) System.out.println(animal.sound());
    
    System.out.println(animals[0] == duck); // => true
  }
}
```
```nim:nimのinterfaceっぽいなにか
type
  Soundable = ref object of RootObj #interface相当の型
    sound:proc ():string
  Duck = ref object of RootObj
  Dog  = ref object of RootObj

proc getSoundable(self:Duck):Soundable= #Soundableを返すメソッド、Javaのimplements相当
  const s = "quack"
  Soundable(sound:proc():string=s) #Duckクラスのsoundの実装相当

proc getSoundable(self:Dog):Soundable= #Soundableを返すメソッド、Javaのimplements相当
  const s = "bow"
  Soundable(sound:proc():string= #Dogクラスのsoundの実装相当
    result.add(s)
    result.add("!!")
  )

let duck = new Duck
let dog  = new Dog
let animals:array[2,Soundable] = [duck.getSoundable,dog.getSoundable]

for animal in animals:
  echo animal.sound() #=>"quack" "bow!!"

echo animals[0] == duck #=>ただし、当然これは型が違うのでコンパイルエラー
```

書いた後に、**nim interface**でGoogle先生にきいてみると、いくつか有用そうなのがヒットした。「Nimにインターフェイスは必要か？」はNimコミュニティでも議論されている模様。

##### [objectではなくtupleでインターフェイス型をつくるパターン](https://www.openmymind.net/Interfaces-In-Nim/)
基本的には上記と同じだが、インターフェイス型相当を`ref object`ではなく`tuple`にしている。

##### マクロでやっちゃうパターン
[interfaced](https://github.com/andreaferretti/interfaced) 
やってることは基本的に上記と同じ模様。`createInterface(インターフェイス名):`でインターフェイスを作り、`toインターフェイス名`でインターフェイス型に変換するマクロになっている。

```nim
import interfaced
createInterface(Soundable):
  proc sound(self:Soundable):string

proc sound(self:Duck) = "quack"
proc sound(self:Dog ) = "bow!"

let duck = new Duck
let dog  = new Dog
let animals = [duck.toSoundable,dog.toSoundable]
for animal in animals:
  echo animal.sound()
```

##### Templete? Concept？ マクロ？
まだ、TempleteやConceptをちゃんと理解できていないので、要調査。

## おわりに ##
インターフェイスもなく、多重継承も認めていないという点で、ちょっと辛いところはあるかもしれないが、十分にオブジェクト指向な設計ができると思う。
まだまだNimはマイナー言語だけど、Go言語よりはやってて楽しい。[^2]　ただ、問題はエコシステムがまだ確立していない。

でもNim超偉い。もっとがんばれ！超がんばれ！

[^2]: 個人の感想、別にGoを批判する意図はない。どう考えても現状はGoの方がエコシステムも完成しているし、実用されている。ただ、「こう書きたいな」というのに、Nimは大体応えてくれるので、書いて楽しいのかなと思う。