至高の言語Nimの欠点

# はじめに
今回は至高の言語Nimの唯一の欠点について話します．
もしかしたら人によっては欠点ではないのかもしれません．
# About Nim
一応，Nimを知らない人用にNimについて書きます(~~そんな奴この記事見つけない説~~)．

Nimは**高速で書きやすい**を目指した言語です．
「記述はpythonなどのスクリプト言語に近く，速度はCと同等」
のようなことを売りにしている言語です．

実際のところは，C(他言語)へと一度変換することで高速にしているといった感じです．
ただ，この変換がなかなかに優秀なので，適当なコードであっても超高速に動いてくれます．

今回は，こんな超優秀(だけど流行らない)言語Nimの欠点について話します．

# NimにShallow Copyはない(2019/06/29訂正)
Nimの欠点．それは**すべてのオブジェクトがDeep Copyされる**ということに起因しています．

~~正確には，**NimにはShallow Copyが存在しません**．~~
(2019/06/29訂正)正確には，**明示しない限り，参照型にならないのでShallow Copyされません**
さらに言えば，**Classオブジェクトや配列オブジェクトは参照型ではありません**
つまり，配列で`=`を使うとDeep Copyされるってことです．
実際の例を見てみましょう
## 固定長配列(array)の場合
### ソースコード
二つの配列arrayAとarrayBを定義して，片方をもう片方へと代入してみます
その後，arrayAのみ要素を変更してみます

```nim
var arrayA, arrayB : array[4,int]
arrayA = [1,2,3,4]
arrayB = arrayA
echo "arrayA ",arrayA
echo "arrayB ",arrayB
arrayA[0] = -1
echo "arrayA ",arrayA
echo "arrayB ",arrayB
```

### 実行結果
arrayAもarrayBも参照型ではないので片方の要素を変更しても，もう片方の要素は変更されませんでした．
つまり，`arrayB = arrayA`がDeep Copyであったということです．

```
arrayA [1, 2, 3, 4]
arrayB [1, 2, 3, 4]
arrayA [-1, 2, 3, 4]
arrayB [1, 2, 3, 4]
```
## 可変長配列(seq)の場合
## ソースコード
可変長配列seqでも同じことをやってみます．

```nim
var seqA, seqB : seq[int]
seqA = @[1,2,3,4]
seqB = seqA
echo "seqA ",seqA
echo "seqB ",seqB
seqA[0] = -1
echo "seqA ",seqA
echo "seqB ",seqB
```

## 実行結果
同様に，片方の要素を変更しても，もう片方の要素は変更されませんでした．
つまり，Deep Copyされたということです．

```
seqA @[1, 2, 3, 4]
seqB @[1, 2, 3, 4]
seqA @[-1, 2, 3, 4]
seqB @[1, 2, 3, 4]
```

# 回避法
では，どうやってDeep Copyを回避するのでしょう？
そのためにNimには`ref`という参照型を明示する記法があります．
要はポインタですね．

## 参照型固定長配列(array)の場合
### ソースコード
参照型のルールは次の三つです．
- 定義に`ref`をつける．
- `new`で領域確保をする．
- `[]`が参照された値を指す．

```nim
var ref_arrayA, ref_arrayB :ref array[4,int]
ref_arrayA = new array[4,int]
ref_arrayA[] = [1,2,3,4]
ref_arrayB = ref_arrayA
echo "arrayA ",ref_arrayA[]
echo "arrayB ",ref_arrayB[]
ref_arrayA[0] = -1
echo "arrayA ",ref_arrayA[]
echo "arrayB ",ref_arrayB[]
```

### 実行結果
両方の配列のは参照元が同じなので，両方とも変更されました．

```
arrayA [1, 2, 3, 4]
arrayB [1, 2, 3, 4]
arrayA [-1, 2, 3, 4]
arrayB [-1, 2, 3, 4]
```
## 参照型可変長配列(seq)の場合
## ソースコード
可変長配列(ほかのクラスオブジェクト)でも同じ．

```nim
var ref_seqA, ref_seqB : ref seq[int]
ref_seqA = new seq[int]
ref_seqA[] = @[1,2,3,4]
ref_seqB = ref_seqA
echo "ref_seqA ",ref_seqA[]
echo "ref_seqB ",ref_seqB[]
ref_seqA[0] = -1
echo "ref_seqA ",ref_seqA[]
echo "ref_seqB ",ref_seqB[]
```

## 実行結果
ちゃんと参照されています．

```
seqA @[1, 2, 3, 4]
seqB @[1, 2, 3, 4]
seqA @[-1, 2, 3, 4]
seqB @[-1, 2, 3, 4]
```

# Nimの欠点
ではこの**すべてのオブジェクトがDeep Copyされる**ことの何が良くないのでしょうか？

Deep Copyするということは，それだけfor文が内部で回るということです．Shallow Copyするよりも確実に速度に影響が出ます．しかも，他言語から移ってきたプログラマは，何気なく`=`を使ってしまうでしょう．そして，速度が落ちていることに気が付かないのです．
実際に検証してみます
## 普通に配列を定義した場合
### ソースコード
要素数100000の配列を定義し，100000回コピーしてみます．

```nim
import times
var start_time = cpuTime()
var arrayA, arrayB : array[1..100000,int]
for i in 1..<100000:
  arrayB = arrayA
echo cpuTime() - start_time
```

### 実行結果
ぼくの環境では平均して5秒程度かかりました．

```
5.216
```

## 参照型で配列を定義した場合
### ソースコード
同様に要素数100000の配列を定義し，100000回コピーしてみます．

```nim
import times
var start_time = cpuTime()
var ref_arrayA, ref_arrayB : ref array[1..100000,int]
ref_arrayA = new array[1..100000,int]
for i in 1..<100000:
  ref_arrayB = ref_arrayA
echo cpuTime() - start_time
```

### 実行結果
わずか0.004秒です．当たり前ですが，参照しているメモリのアドレスのコピーなので時間がかかりません．

```
0.004000000000000448
```

# おわりに
Nimの`=`はなかなかのトラップです．しかも，クラスオブジェクトに対しても同様の挙動を示すというところがもう...
いちいち`ref`で定義しなければいけないし，`ref`で定義すると，今度は`[]`が必要になるし．

高速で書きやすい言語に移住してきたのに，**「高速にするためには書きにくい表記をしなければならない」**というのがNimの最大の欠点でしょう．