Nim ざっくり勉強してみたまとめ

チュートリアルを読み切ったので自分用メモ。競プロと相性良さそうだし使ってみようかなと思って勉強したら AtCoder の Nim めっちゃ古くて泣いた。でも面白そうな言語。 C にトランスパイルされる Lisp に Python の皮を被せたみたいな趣を感じる。演算子周りは Haskell っぽい風情もある。

今時の言語らしくいろいろ便利記法が用意されてて、実用的っぽい。やたらシンタックスシュガーが多い言語は個人的には好きじゃないけど、これくらいならアリかも。インデントでブロックを作るのはまあ、そこは時代の流れっぽい。

書きやすさ、安全さ、実行効率のバランスの取り方がかなり独特で面白い（for 文にナチュラルにループのアンロール回数を指定する記法とか生えてるのやばない？）。こんなふわっと書けて C と同等に速いのはすごい。言語仕様を見てるとヒープにアロケートされるオブジェクトがなるべく少なく済むように意識した設計になっていそうで、その辺が速さに効いてるのかな (ヒープにアロケートすると GC 管轄になる)。ライフタイムなどをすべて管理する Rust もカッチリしていて綺麗だけど、これはこれで良い感じの落とし所っぽく見える。中間コードが human readable な C なので、デバッグでいきなりバイトコードまで潜らなくていいのも良さげ。

大半のビルトインが暗黙にロードされる `system` モジュールとして nim 自体で実装されている (self-contained) らしい。 hackable だし、問題があった時にソースに当たりやすいし、コアも小さくなるので良い方針だと思う。ドキュメントを書くためのコメント構文とかも用意されてて、この辺は lisp 系っぽい感じがする。同図象性も入っていて、構文木をゴリゴリやる系のマクロも書ける。さすがに lisp よりはしんどいけど…。

以下、概ね Nim 公式の "Nim Tutorial (Part I - III)" の超ざっくり要約。

## I/O

- `stdin` からメソッドが生えてる

```nim
let s = stdin.readLine # 一行読み込む
```

- 競プロ的には `strutils` の `split`、`sequtils` の `map` と併用することが多そう

``` nim
import strutils, sequtils

let lst = stdin.readLine.split.map(parseInt) # 整数のリストが得られる
```

- `echo` はなんでもいい感じに出力 (改行付き)

``` nim
echo 30
```

## 変数

- `var` はミュータブル、 `let` はイミュータブル、 `const` はコンパイル時定数 (!!)

- 型か初期値の少なくとも一方が必須 (型だけを与えると「その型のデフォ値」がセットされる (!!))

``` nim
var hoge: int # 0 になる
let fuga = 1
const piyo : string = stdin.readLine # コンパイル時に確定しないのでエラー
```

- 一括初期化もできるけど、 *最適化のために右辺の式はアンロールされて複数回呼ばれることがあるので副作用に注意 (!!)*

``` nim
var
  x, y : int
  a, b, c = "hoge" # a, b, c は全部 hoge になる
```

この辺のアグレッシブな感じ尖ってて好き。ここでハマったら半日くらい帰ってこれなさそう。

## 分岐

- 条件は括弧で囲む必要なし

- `elif`

``` nim
if hoge == 1:
  echo "hoge"
elif hoge == 2: # else: if: だとインデントややこしいので elif
  echo "fuga"
else:
  echo "piyo"
```

- `case` もある (パターンマッチというよりは C の switch 文っぽい？)

- パターンが期待されているところに range っぽいものを書くといい感じになる

``` nim
case n # ここには ':' がつかないっぽい
of 1:
  echo "1"
of 2..4, 7..9:
  echo "2~3 or 7~9" # 範囲も使える
else:
  discard # 使わない場合は明示的に discard
```

静的な網羅性チェックがあるので `else` 忘れるとコンパイルエラーにしてくれる。

- `when` はコンパイル時に静的に展開される (`#ifdef` みたいな感じ)

``` nim
when system.hostOS == 'windows': # 普通に nim の式が書ける (!!)
  echo "windows!!"
```

## ループ

- `while` は普通

``` nim
while hoge == "":
  hoge = stdin.readLine
```

- `for` は `<var> in <iterator>` の形式オンリーっぽい

``` nim
for i in countup(1, 10):
  echo i
```

- iterator が期待されている場所に range っぽい記法を使うといい感じになる

``` nim
for i in 10..1: # countdown(10, 1) と同じ
  echo i
```

``` nim
for i in 1..<8: # < をつけると exclusive になる
  echo i
```

- コレクションにはだいたい `items`, `pairs` が生えていて iterator を取れる
  - しかも省略可っぽい…？あとでそういう例が出てきた。もしかすると seq 限定かも

``` nim
for i in [1, 2, 3].items:
  echo i
```

``` nim
for (ix, i) in [1, 2, 3].pairs:
  echo (ix, i)
```

## その他の制御

- `break`, `continue` が普通にある

- `block` はスコープを作る他に、名前をつけて大域脱出にも使える

``` nim
block hoge: # 名前がつけられる
  while hoge:
    while fuga:
      break hoge # 名前を指定して break できる
```

## 改行ルール

- 単一の代入文、関数呼び出し、 `return` 文は改行を省略できる

``` nim
if hoge: echo "hogehoge!!"
```

- それ以外 (`if`, `when`, `for`, `while` などのネスト) は改行必須

``` nim
if hoge:
  if fuga: echo "hogefuga!!"
```

- 式の途中は自由に改行してよい

``` nim
if hoge(
     1, 2, 3,
     4, 5, 6
   ) and fuga (
     7, 8, 9
   ):
  echo "hogefuga!!"
```

- 文を `;` で区切って括弧に放り込むと、値を返す式として使える

``` nim
const hoge = (var x = 0; for i in 1..10: x += i; x); # しかもコンパイル時計算！
```

- 極端な例では、関数呼び出しの最後の引数をブロックで計算してしまうこともできる

``` nim
echo "Hello ":
  var bikkuri = '!'
  "Wor" & "ld" & $bikkuri
```

## 関数

- `proc` で定義、型は手書き

チュートリアルには登場しなかったけど実は `auto` もあるっぽい

- 値の返し方がいろいろある

``` nim
proc hoge (foo: int): bool =
  foo == 2 # 最後に評価した式が返る


proc fuga (foo: int): bool =
  if foo < 4: return false; # return で先に返す
  true

proc piyo (foo: int): int =
  for i in 1..foo:
    result += i # result という変数が暗黙に定義されるので、そこに結果を貯める
```

`result` 強烈だけど便利そう。「最後に評価した式が返る」パターンと「`result` が勝手に返る」パターンがコンフリクトしそうに見えるけど、 `result` 変数を一度も使っていなければ最後に評価した式が返るっぽい。

- 引数に `var` をつけると関数側からその変数を書き換えられる

``` nim
proc assign (foo: int, bar: var int) =
  bar = foo

var hoge;
assign(2, hoge) # hoge に 2 が入る
```

フィールドもいじれるっぽいので lisp の `setf` みたいな仕組みが入っていそう。 `hoge[2] = 3` とか書いたときの `[]` 演算子も同じような仕組みになってるんだろうか。この辺はエレガントだなあ

- 第一引数を外に出してメソッドチェインみたいに書ける。１引数関数の場合 `()` は省略可

``` nim
proc addOne (foo: int) =
  foo + 1

echo 2.addOne # addOne(2) と同じ意味
```

Perl っぽい。とても好き

- 戻り値を捨てる場合は明示的に `discard`

``` nim
proc hoge () : int =
  echo 2
  100

discard hoge() # 副作用だけが欲しい場合は明示的に discard しないとエラー
```

``` nim
proc hoge () = # 戻り値の型を省略すると値を返さない関数になるっぽい
  echo "hoge!!"

hoge()
```

``` nim
proc hoge () : int {.discardable.} = # 値を返しつつ pragma で discard を省略可にもできる
  echo 2
  100

hoge()
```

C とかだと `(void)` つけて警告消したりするけど、このほうがよっぽど良さそう。

- default value 付きの引数とか名前付き引数もいける。現代的

``` nim
proc hoge (foo: int, bar: int = 3) : bool =
  foo + bar

echo hoge(foo = 2)
```

- 型ごとにオーバーロードすると静的型を見て適切にディスパッチしてくれる

``` nim
proc foo (foo: int) =
  echo foo + 1

proc foo (foo: string) =
  echo "string"
```

- 相互再帰などでは C 言語のように forward declaration が必要 (将来なくなる可能性アリらしい)

``` nim
proc hoge (foo: int) : int
```

- 関数の型もまとめて書けるっぽい

``` nim
proc hoge (foo, bar: int; baz: string) : int # まとめて書く場合はセミコロンで区切るっぽい
```

## 演算子

- 演算子も全て関数、バッククォートで囲むとユーザー定義もできる

``` nim
proc `+?` (foo: int, bar: int) : int =
  foo + bar + 1

echo 3 +? 2

echo `+?`(1, 2) # 関数のシンタックスでも呼び出せる
```

演算子に使える文字は `+-*\/<>=@$~&%!?^.|` のみ。組み込みの `and`, `or`, `not` などは特別枠。

１引数にすれば prefix、２引数にすれば infix。 postfix は原則ナシ

- 配列などのインデックス参照 (`[]`) も特別なオペレータとして実装されているっぽい

## イテレーターの自前実装

- `proc` を `iterator` に変えればイテレーターが書ける

- 値を返すときは `yield`

``` nim
iterator range(a, b: int) : int =
  for i in a..b
    yield i
```

- イテレーターでは再帰呼び出しが禁止される (実装上の都合なので将来的にはいい感じにしたいとかなんとか)

- イテレーターと関数の名前空間は別になっているので、名前被りは ok

## 基本型
### `bool`

- `true` または `false`

- short-circuit な  `and`, `or` 演算子と、 `not`, `xor`, `==`, `!=` 演算子が使える

- なぜか順序系のオペレータも定義されてる `<`, `<=`, `>`, `>=` (`sort` とかで便利って感じなのかな)

### `char`

- シングルクォートで囲んで表現

- C 言語同様１バイトなので Unicode とかは無理

- ただし `int8` とはちゃんと区別されるので、 `ord`, `char` 関数で明示的に行き来する

- `int8` ではないので四則演算はなし、大小比較だけができる

### `string`

- 「string は mutable」って書いてあるけど `let` だと変更できなかったので、あたかも新しい値が作られて再代入されたかのように振る舞ってそう
  - 他のコレクションっぽい基本型も同様 (試した)。さらにネストされてる場合はディープコピー
  - たぶん `ref` (後述) とか使って参照を増やしたりしない限り基本 immutable。いい感じ

``` nim
var hoge = "hoge"
hoge[2] = 'i'

echo hoge # hige
```

- `len` メソッドで長さが取れる

- `&` オペレータで concatenate、 `add` オペレータで append

- `[]` オペレータで各バイト (unicode でない) にランダムアクセスできる

- 辞書順で順序が定義されている

### `int`

- 符号付き整数

- 桁数が足りなくなると最大 64bit までよしなにキャストされる

- 後ろにビット数をつけると明示もできる (`int8`, ..., `int64`)
  - リテラルでビット数を明示したい場合は `10'i8` のように書く

- 四則演算と順序が定義されている。割り算は `/` ではなく `mod`, `div`

- ビット演算もあるが、unsigned かのように振る舞うので算術シフトが欲しい場合は `div 2` する必要がある (!!)
  - `and`, `or`, `xor`, `not`, `shl`, `shr`

- リテラルの途中のアンダーバーは無視される (`1_000_000` のように書いても良い (!!))

- リテラル先頭の `0x`, `0b`, `0o` でベースを指定できる。 `012` とかは普通に十進扱い

これ地味にトラップなので嬉しい。

### `uint`

- `int` に似ているが、 `0` より小さくならない (アンダーフローもしない)

- 上限に到達した場合も同様にオーバーフローしない

- たんに負にならないことを型として明示したいだけなら、あとで出てくる `Natural` を使うべき

### `float`

- IEEE754 浮動小数点数

- `int` と同様にビット数の指定ができる (`float64`, `0.5'f64` など)

- 四則演算と順序が定義されている。割り算は `/`

- `toInt`, `toFloat` で整数と行き来できる

### ordinal types (順序型？)

- `int`, `char`, `bool` と、このあと出てくる `enum ...`, subrange には以下のオペレーションを共通で使えて、これらを総称して ordinal type と呼ぶ
  - `ord`, `inc`, `dec`, `succ`, `pred`

### キャスト

- 型名を関数 (メソッド) のように使ってキャストできる

``` nim
let x = int(2.5)
let y = 'a'.int8
```

## 文字列変換

- たいてい `$` メソッドが定義されていて、いい感じの文字列に変換できる

- `repr` メソッドでは内部表現を得られる

## 複雑な型

コレクションっぽい型もあるけど、明示的に new したもの (後述) の参照以外は value type なので再代入でディープコピーされる

### 型定義

- `type` 文で型の別名を定義できる

``` nim
type
  longlong = int64
  ulonglong = uint64 # 複数もいける
```

### `enum; <name>, <name>, ...`

- C の `enum` 同様、`0`-origin で勝手に番号が振られる

``` nim
type
  Direction = enum
    north, east, south, west

var x: Direction = south
```

- 名前がかぶる場合は `.` で型を明示できる

``` nim
var x = Direction.south
```

- `$` は自動でいい感じに定義される

### `range[<from>..<to>]` (subrange)

- ordinal type の一部だけを切り出した型

``` nim
var hoge : range[1..3] = 3
```

- たとえば組み込みの range `Natural` が `range[0..high(int)]` (`high` はその ordinal type の最大値) として定義されているので、正の数であることを明示したいときはこれを使うと便利

### `set[<ordinal type>]`

- 高速な代わりに ordinal type しか格納できない set
  - もっと複雑なものを格納したい場合は標準ライブラリにある HashSet などを使う

- bit vector で実装されているので `2^16` 以上の値は突っ込めない

この辺の割切り感も「らし」くていいなあ。

- リテラルは `{}`、中で range らしきものを書くといい感じに解釈される

``` nim
var x: set[char] = { 'a'..'z', '0'..'9' }
```

- 四則演算 (和集合、共通部分、差集合 etc) が定義されている

``` nim
var x: set[char] = { 'a'..'z' } + { '0'..'9' } - { 'b' }
```

- サブセット関係で順序も定義されている。おしゃれ

- 特定の要素が入っているかは `in`, `notin` オペレータか `contains` メソッドで調べられる

``` nim
echo ('a' in x)
```

- 要素の追加削除は `incl`, `excl` メソッド

- 要素数は `len` ではなく `card`。おしゃれ

### `array[<size>, <type>]`

- 固定長の配列

``` nim
var x: array[2, int] = [1, 2]
```

- `array[<from>..<to>, <type>]` とするとインデックスの範囲を変えられる (!!)

``` nim
var x: array[2..4, int] = [0, 1, 2]
echo x[2] # 0 が表示される
```

これ地味に便利だなー

- `len` で要素数、 `low` で一番小さい index, `high` で一番大きい index (inclusive)

- 要素のセットは直感的な構文でできる

``` nim
x[2] = 4
```

- 二次元配列は配列の配列として定義する

``` nim
var x : array[2, array[2, int]]
```

----

なんとなく型検査のアルゴリズム（というか equality の定義）を眺めていたら `indexType`, `baseType` という文字列が見えたんだけど、もしかして配列の大きさとして書く `array[1..3, int]` の `1..3` とかは型 (subrange) で、同様に型のレイヤーでは `2` は `0..2` の subrange を表すとかそんな感じになってるのかしら（未検証）。だとしたら `[int, int]` とか書いたらどうなるのか気になる。面白そうな言語だしちゃんとマニュアルも読みたいな。

### `seq[<type>]`

- 可変要素数の配列

- heap にアロケートされる (実行効率に気をつけてねという意味だと思う) が、 value type なので再代入すると deep copy される

- `@[]` で簡単に作れる

- arr と同様に `len`, `low`, `high` などが定義されている

### `openArray[<type>]`

- 不定長の配列

- コンパイル時に長さを確定できない配列を受け取るのに使う、実体は固定長配列なので動的に伸ばしたり縮めたりはできない

- 引数の受け渡しが完了すれば `seq` と同様のメソッドが使える

- ネストは実装上の都合でできない

この辺 C が見え隠れしてて好き…

### `varargs[<type>]`

- 不定長の配列

- 可変長引数の関数を書くのに使う

- 引数の受け渡しが完了すれば `seq` と同様のメソッドが使える

- 引数がミックスされていた場合は暗黙に変換される

``` nim
proc hoge (foo: int, bar: varargs[string]) : string =
  ...

echo hoge(1, 2, "hoge") # 2 は string に変換される
```

`discard` とか安全性もちらほら気にしているように見えるのに、ここはエラーにしないのはなんか理由があるのかしら…

### `HSlice[<type>, <type>]`

- 二項演算 `..` によって作られる「範囲」を表すオブジェクト
  - `case` のパターンでも似た構文は出てきたが、こちらはれっきとしたオブジェクト

- `string` などのシーケンス型は `[]` 演算子にスライスも受け取れるようになっているので、 substring を簡単に取得したり差し替えたり (!!) できる

``` nim
var hoge = "hogehoge"
hoge[2..3] = "gi"

echo hoge # hogihoge
```

イテレーターでも同じような構文が使えたけど、これはイテレータと関数で名前空間が違うことをうまいこと使ってるのかな。よくできてるな…

- イテレータと同様 `..<` 構文も使えるのに加えて、後ろから数える `^n` も使える

``` nim
hoge[1..^1] # 頭１文字とケツ１文字を捨てる
hoge[^2..^0] # 後ろ３文字を取る
```

特に後者ができるのすごい、構文どうなってるの…。これが許されるなら `hoge[^1]` とかも書けそうに見えてしまうけどそれはできないっぽい。若干トラップ

### `object; <name>: <type>; ...`

- 基本的なレコード型

- 型名に `*` を付与するとその型自体が、フィールド名に `*` を付与するとそのフィールドが外のモジュール (ファイル) から見えるようになる

``` nim
type
  Foo* = object
    hoge* : int
    fuga : int # こっちは private なフィールド
```

- リテラルは `Constructor(<...args>)` 形式

``` nim
var hoge : Foo = Foo(hoge: 1, fuga: 2)
```

- 相互再帰的な型も単一の `type` 文で宣言できる

``` nim
type
  Hoge = ref object # 型自体を ref にしてもよいし、
    foo : ref Fuga # フィールドを ref にしてもよい
  Fuga = object
    foo : Hoge
```

- `case` で union っぽいのも作れる

``` nim
type
  ObjType = enum
    Hoge, Fuga
  Obj = object
    case type: ObjType # type は種類を表すフィールドになる
    of Hoge:
      hogeVal: int # type が Hoge だった場合のフィールド
    of Fuga:
      fugaVal1: int
      fugaVal2: string

var hoge : Obj = Obj(type: Hoge, hogeVal: 1)
var fuga : Obj = Obj(type: Fuga, fugaVal1: 2, fugaVal2: "fuga!")
```

- `<fieldname>=` で setter を定義できる

``` nim
type
  Obj = object
    foo = 1 # このフィールドは private

proc bar* (obj: Obj) : int =
  $obj.foo & "!!"

proc `bar=`* (obj: Obj, val: int) =
  obj.foo = val - 1

var hoge : Obj
new(hoge)

hoge.bar = 1 # 代入の構文を使うと setter が呼ばれる
echo hoge.bar # "0!!"
```

- `[]=` でインデックス記法の setter も定義できる

``` nim
proc `[]=`* (obj: Obj, index: int, val: int) =
  if index == 0:
    obj.foo = val - 1

hoge[0] = 100
echo hoge # "99!!"

hoge[1] = 200
echo hoge # "99!!"
```

### `tuple; <name>: <type>; ...`

- object と同じことができるが、いくつか追加の特徴がある

- 型名をつけずに使うことができる

``` nim
var hoge : tuple[foo: int, bar: int] = (foo: 1, bar: 2)
```

型の equality は構造によって決まる。フォーマットが同じなら同じ型扱い

- フィールド名もつけずに使うことができる

``` nim
var hoge : (int, int) = (1, 2)
```

- 解体は分割代入でできる

``` nim
var (hoge, fuga) = (1, 2)
```

- `tuple.fieldName` や `tuple[1]` でも内容にアクセスできるが、インデックスは定数でないとダメ

### `ref <type>`

- いわゆるポインタ、 `new(<var>)` を使って明示的にヒープにアロケートしたオブジェクト (traced object) に対して使う
  - traced object は GC の管轄に入る

``` nim
var hoge : (int, int)
new(hoge)

var hogeRef : ref (int, int) = ref hoge
```

- `<ref>[]` で deref できる
  - `<ref>[][1]` は `<ref>[1]` と書ける (暗黙に deref される)

``` nim
echo hogeRef[]
```

### `ptr <type>`

- `ref` とだいたい同じだが、 `alloc`, `dealloc` で自力でメモリ管理する (untraced object)

- GC の管轄外になるので実行時エラーの原因になりうる、基本的には使わない

低レイヤの操作も言語レベルで許されてる感じ好き

### `proc (<name>: <type>, ...) : <type>`

- 関数の引数や変数に `proc` を渡したいときに使う型

- 第一級関数っぽいけど実は関数ポインタなので `nil` も渡せる

- 呼び出し方を `pragma` で選べる
  - `proc (foo: int) {.inline.}` でインライン化、など
  - 呼び出し方は型レベルで区別されるので、呼び出し方の合わない関数は渡せない

マニュアルを見ると「呼び出し方」も相当いろんな種類がビルトインされてて最適化 / 低レイヤへの気概を感じる…。

- `proc` 内で定義した `proc` や、 proc type のオブジェクト (関数ポインタ) は呼び出し方が暗黙に `closure` になる
  - 裸の `proc` は `closure` ではないので厳密には区別されるが、 `closure` の期待されているところに裸の `proc` を投げるのは例外的に ok (なので普段はあまり気にする必要ない、グローバルな関数以外は環境を持ち回るんだなあくらいの認識で ok)

### `distinct <type>`

- 元の `<type>` と同じデータ表現を持ちつつ、互いに subtype の関係にはない型

``` nim
type
  Hoge = distinct int

var
  hoge : Hoge = 1 # int と同じデータを持てる
  fuga : Hoge = 2

echo hoge + fuga # int の subtype ではないので `+` が未定義 → これはエラー
```

一瞬謎の機能に見えるけど、マニュアルを読みに行くと `SQL` を `distinct string` で定義するユースケースとかが載ってる。 `SQL` にサニタイズを強制すれば SQLi 対策になる。生の文字列連結とか危険なオペレータが全部未定義になるので安全

## ジェネリクス

- 型、関数などにはジェネリクスをつけられる

``` nim
type
  Tree*[T] = ref object
    l, r : Tree[T]
    val: T

proc newNode*[T] (val: T, l: Tree[T], r: Tree[T]) : Tree[T] =
  new(result) # result 変数もヒープにアロケートできる
  result.val = val
  result.l = l
  result.r = r
```

## モジュールシステム

- モジュールはファイル

- グローバル変数やメソッドも名前の後ろに `*` をつければ export できる

- import は `import <Module>, <Module>,...` でできる

``` nim
import hoge, fuga
import piyo except dosukoi # dosukoi 関数はいらない
from piyo import dosukoi # dosukoi 関数だけ欲しい
import hoge as h # 別名
```

- C のような `include <file>, ...` もできる。多分 private なものにも全部アクセスできる。単純にファイルだけ分けたいときに使うっぽい

- export されているシンボルが名前被りした場合は `ModuleName.symbol` で明示できる (メソッドで型が違う場合などはよしなにディスパッチされるので大丈夫)

## OOP (継承)

前書きに「OOP の強力なコンセプトも使えるけど nim の OOP はミニマルだよ。 OOP は便利だけどいつも正解とは限らないよ、 inheritance より composition の方が良い場合も多いよ」とある。好き

- `object of <baseClass>` で継承システムを有効にできる

- ルートは `RootObj`

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

「nim では継承を使うことは完全に任意だが、もし実行時の型情報を使って継承関係を作りたいなら…」という表現が、これは nim のデフォルトのモデリング手法というわけではないんだぜ感をめちゃくちゃ出してて好き

`{.inheritable.}` プラグマ を使えば `RootObj` を継承することなく継承システムを有効にすることもできる

- 型名でダウンキャストできる

``` nim
proc getID (x: Person) : int =
  Student(x).id
```

ダウンキャスト不可なオブジェクトだった場合は実行時エラー

- `method` で動的にディスパッチする関数が書ける

``` nim
type
  Expr = ref object of RootObj
  Literal = ref object of Expr
    val: int
  Add = ref object of Expr
    l: Expr
    r: Expr

method eval (e: Expr) : int =
  quit "OVERRIDE ME!"

method eval (e: Literal) : int =
  e.val

method eval (e: Add) : int =
  eval(e.l) + eval(e.r)
```

`eval` は `Expr` ならなんでも渡せるが、渡ってきたものの種類によって動的に振る舞いが変わる。 (`proc` も多重ディスパッチはできるが、型によってどの関数が呼ばれるかは静的に決まるのが違い)

コンパイル時に `--multimethods:on` をつける必要がある

## 例外

- `HogehogeError` 系の型は例外オブジェクトを表す

- どれも `Exception` を継承していて、エラーの詳細が入っている `msg` フィールドを持っている

- `raise` で発射できる

``` nim
raise newException(HogehogeError, "Oops!")
```

exception は必要なライフタイムが不明なので (`newException` で) ヒープにアロケートする必要がある。

- `try`, `expect`, `finally` で例外をキャッチできる

``` nim
try:
  let a = readLine(file)
except IOError:
  echo "IO Error!"
except: # 残りの例外を全部ハンドル
  echo "Unexpected error!"
  raise # 引数なしの raise は直近の例外を re-raise
finally:
  close(file) # 必ず最後に実行される
```

キャッチされない例外があったらそのまま親に渡っていき、誰もキャッチしなければ (`finally` だけ実行して) 死ぬ。

- `{.raises: [...].}` プラグマを書くとそこにリストされていない例外が飛ぶ可能性がないか静的に検査してくれる

すごい。 Effect System というのの一部として実現されているらしく、実際にはもっと色々できるっぽい

## テンプレート

- 単純なマクロはテンプレートとして書ける

- 型を指定するとマッチした場合だけ展開できるっぽい。 `untyped` なら何も考えずにいつも展開

``` nim
template `!=` (a, b : untyped) : untyped =
  not (a == b)
```

実際 `!=` はこのように定義されている (`>`, `>=`, `in`, `notin`, `isnot` なども同様)。関数でもいいように見えるが、こうしておくと `==` をオーバーロードするだけで `!=` が適切に動くようになって便利。たしかに

- `const` とテンプレートを組み合わせる例

``` nim
const
  debug = true

template log (msg: string) =
  if debug: echo(msg)

var x = 3
log("x is " & $x)
```

コンパイル時に `debug` の値が分かっていれば、関数呼び出しまるごと消せるので引数の評価 (`&`, `$` の処理) 分だけ実行効率を稼げる。賢いなあ

- ブロックが書かれた場合は最終引数に渡る

``` nim
template withFile (v: untyped, filename: string, mode: FileMode, body: untyped) =
  let fn = filename # filename を複数回使うのでここで eval しておく
  var v: File
  if open(v, fn, mode):
    try:
      body
    finally:
      close(v)
  else:
    quit("cannot open file " & fn)

withFile(file, "someText.txt", fmWrite):
  file.writeLine("hogehoge")
```

これって `v` はちゃんと `body` でキャプチャされつつ、 `fn` はハイジニック (名前被ってもよしなに `gensym` される) になってるのかな。きっとそうなんだろうな、すごいなあ…

----

`!=` なんかがテンプレートで定義されているの、一瞬賢いなあと思ったけど、しばらく使っているうちに、「これ普通に型レベルでインターフェース決まってた方が嬉しいわ (cf. Haskell の Ord 型クラス)」という感想になってきた。たとえば順序系の比較演算 `<`, `<=`, `>`, `>=` なんかもテンプレートで定義されていて、確か `<` と `=` かな？だけ実装すれば残りは実装しなくても使えるとかだった気がするけど、そんな仕様覚えてられない…w

## マクロ

- 構文木オブジェクトを直接ゴリゴリする lisp 的なマクロも書ける

``` nim
import macros

macro myAssert(arg: untyped): untyped =
  arg.expectKind nnkInfix # 中置記法以外がきたらエラーにする
  arg.expectLen 3 # 演算子、オペランド x2 の３要素が揃っていなかったらエラーにする
  let op  = newLit(" " & arg[0].repr & " ") # 演算子ノードから文字列リテラルを作る
  result = quote do: # lisp の quasi-quote みたいな感じ、構文木オブジェクトが生成できる
    if not `arg`:
      raise newException(AssertionError,$`arg[1]` & `op` & $`arg[2]`)
```

この定義のもとで

``` nim
myAssert(a != b)
```

は

``` nim
if not (a != b):
  raise newException(AssertionError, $a & " != " & $b)
```

に展開される。カッコが勝手に補われているあたり構文木を直接いじっているんだなあいう感じがある

開幕の

```
arg.expectHogehoge
```

は良い感じのコンパイルエラーを生成するために必要。検査に通ればマクロの展開にコケることはない状態が好ましい。

- 引数を `static[<type>]` にすると式自体ではなく静的に計算された具体値が渡ってくるっぽい
- 引数を `typed` にすると、任意の型を受け取りつつ実際に型推論が判定した型の情報も見えるっぽい