2019/04/24

Nimのちょっとおもしろい機能distinct

distinct

Nimでは型に別名をつける機能が実は2つあります。一つは本当に単なる別名をつけるもの。もう一つは元々ある型を使って、全く新しい型を作るというもの。
まず前者のほうは以下のようになります。

type MyArr = array[5, int]

var arr: MyArr

arr = [1, 2, 3, 4, 5]

doAssert(arr == [1, 2, 3, 4, 5])

これは単なるエイリアスです。C言語のtypedefやRustのtypeと同じ感じです。そして後者のほうは以下のようになります。

type Num = distinct int

proc `+`(x, y: Num): Num {.borrow.}
proc `$`(n: Num): string {.borrow.}

var
  a = Num(5)
  b = Num(6)
  
doAssert($(a + b) == "11")
distinctは英語で、「全く異なった」とか「独特の」という意味ですが、このキーワードを使って別名を作成すると、例えば上記の場合、本来int型が持っているメソッドが全く使えなくなり、新たな形で独自のint型を作成できます。そして、もしその新たな型でも例えば上記のように足し算や文字列へのキャストなど通常は使える機能を使いたい場合、{.borrow.}プラグマで借りてきてオーバーライドして使うことができるようになります。摩訶不思議なり。
まだ使いこなせているわけではないので、あくまでも私の勝手なイメージですが、この機能を使うと全く別の言語を作成できるのではないかと思います。何せ欲しい機能は借りてきて、違う動作を求めるのならば独自に定義すればよいのですから。何とも掴みどころのない、奥の深い言語だこと。