2019/09/28

Nim version 1.0.0 ついにリリース

前回の記事にて……

前回の記事で、Nimはversion1までは様子見すると言って、のんびり構えていたら、もうリリースされてしまいました。ということで、これからNimを始めようという方のために、まだまだ日本語の情報が少ないので、大まかな使い方や仕様を書いていこうかと思います。

Nimはガベージコレクタ・型推論付きのコンパイラ言語で、たとえばHello worldプログラムを作ってやってみます。

---------
hello.nim
---------

echo "Hello, world"

一行だけのプログラムですが、ちゃんと出力します。

$ nim c -r hello.nim
.
.
.いろいろ表示される
.
Hello, world
この場合、.cacheディレクトリ(私の場合)にhello.nim.chello.nim.c.oとその他諸々のファイルが作成されます。そして、作業中のディレクトリには実行ファイルhelloが作成されます。

$ ls
hello hello.nim
$ ./hello
Hello, world
一見すごくシンプルな言語に見えますが、実は結構難しい言語なのではないかと、個人的には思っています。

Nimの大まかな文法

変数
型については公式ドキュメントを読むことをおすすめします。と言いますのは、基本型は大体どの言語も大体同じ感じなのですが、Nimの場合、関数の仮引数に使用可能な型やreturnの時に使える型やマクロ作成時に使える型など特別なときにのみ使用できる型も存在するからです。少しややこしい。
さて変数宣言についてですが、こちらも2種類存在します。letvarです。前者はイミュータブルつまり変更不可。後者はミュータブルつまり変更可。したがってletで宣言した変数に値を代入しようとするとエラーになります。

let x: int = 3
x = 5  # ERROR!!

var y: int = 3
y = 5 # OK!!
関数
関数は意外とややこしいです。resultという特別な変数があったり、discardという戻り値を破棄するものがあったりします。
関数を定義する際も2種類(おまけ的に)あります。procfuncです。funcは割と最近導入されたもので、副作用を許さない関数です。例えば以下のような副作用のある関数でfuncを使うとエラーになります。

func hello() =
  echo "Hello"
  
hello()  # ERROR
これは以前まで以下のようにプラグマを使って、書いていました。

proc hello() {.noSideEffect.} =
  echo "Hello"
  
hello()  # ERROR
コンパイルの際に副作用の有無を確認できるという感じです。
構造体・列挙型
Nimではtypeを使って定義します。

type
  Person = object
    name, email: string
  
var p: Person

p = Person(name: "Nim", email: "nim@nim.com")

echo p  # (name: "Nim", email: "nim@nim.com")
しかし上記のやり方だとメモリ効率がよろしくない(スタック領域を使う)ので、以下のような参照型を使ったやり方(ヒープ領域を使う)が一般的なようです。

type
  Person = ref object
    name, email: string
  
var p: Person = new Person

p = Person(name: "Nim", email: "nim@nim.com")

echo p.name, ", ", p.email  # Nim, nim@nim.com
列挙型もまたtypeを使います。

type
  MyEnum = enum
    A, B, C
    
var a = MyEnum.A

echo a  # A
ここで{.pure.}プラグマを使うことができるのですが、使っても使わなくてもさして変化が分からない。ちょっと疑問。違いの分かる方、ぜひ教えて下さい。
条件分岐
条件分岐はif~elif~elseおよびcase~of~elseがあり、これは以下のような書き方になります。

var x = 30

if x.mod(15) == 0:
  echo "FizzBuzz"
elif x.mod(5) == 0:
  echo "Buzz"
elif x.mod(3) == 0:
  echo "Fizz"
else:
  echo $x
  
 
var x = 'A'

case x:
of 'A': echo true
else: echo false
反復
反復処理にはwhileforがあります。

var x = 0

while x < 10:
  echo x
  x.inc()

for i in 0 ..< 10:
  echo i
defer
Nimにはdeferというものがあります。いわゆるtry~except~finallyfinallyの部分と同じです。使い方は簡単。

block:
  defer: echo "finish"
  echo "start"
  
-------
出力結果
-------
start
finish
deferはトップレベルでは使えないので、blockを使っています。blockはラベルをつけることもできます。

block deferExample:
  defer: echo "finish"
  echo "start"

おおざっぱなまとめ

Nimは見た目とは裏腹に、なかなかの歯ごたえの言語ではないかと思います。使いこなせればきっと面白い言語なのだろうな、とは思いますが、ワタクシ的にはRustよりも難しい上に、いまいち納得できないところがあったりします。しかし、まだまだ若い言語でありますので、今後どのようになっていくのか楽しみな言語なので、勉強は怠らないようにしようと思います。