読者です 読者をやめる 読者になる 読者になる

Nim帳

プログラミング言語Nimについて書いていきます。

20160921155215

Nimのモジュール

Nimは普段のプログラミングに使える汎用のプログラミング言語ですが、 言語としてはシステムプログラミングを意識している言語です。
システムプログラミング言語としてはC/C++がメジャーな言語ですが、NimではC/C++と違って優秀なモジュールシステムを使うことができます。
今回はそんなモジュールの話です。

基本

基本的にはpython風の文法になっています。

import

Nimのモジュールシステムで他のモジュールを使うようにするには、

import モジュール名 

と書くことによって使えます。
例えば、標準ライブラリでよく使うstrutilsをimportするには

import strutils

とすればすぐに使うことができます。

except

importする際に一部の関数などをインポートしないようにするexceptがあります。

import strutils except `%`, toUpper

echo "$1" % "abc".toUpper # compile error!

from

他にも、特定の関数のみをインポートするfrom文があります。

from strutils import `%`
echo "$1" % "abc"
echo strutils.replace("abc", "a", "z") # モジュール名を含む場合使用可能

importはカンマで区切ることによって1行で複数モジュールをインポートすることができます。

import strutils, sequtils

さらに、asで別名にすることができます。

import strutils as su

インポートした関数などは、そのまま関数名で呼び出すことができ、strutils.formatのように呼び出すこともできます。
別のモジュール同士に同じ関数名が含まれている場合は、モジュール名をつけることによって区別することができます。

# modulea.nim
proc echoInt*(a: int) =
  echo a
# moduleb.nim
proc echoInt*(a: int) =
  echo a
import modulea
import moduleb

echoInt(1) # compile error!
modulea.echoInt(1) # works!
moduleb.echoInt(1) # works!

Nimのモジュールシステムではimport モジュール名とした際に、

  • 標準ライブラリ
  • パッケージマネージャのnimbleによってインストールされたライブラリ
  • ディレクト

からインポートしようとします。

インポートする際にはモジュール名に相対パスを使うことができ、相対パス/.に置き換えることもできます。

# modules/foo.nim
proc echoInt*(a: int) =
  echo a
import modules.foo

echoInt(1)

Asterisk(public)

サンプルの関数に付いているアスタリスク*は関数を公開(public)するようにする文法です。
関数以外にもマクロや型などにも付けることができます。

export

他モジュールの関数などを別モジュールから公開するexportがあります。

# objmodule.nim
type MyObject* = object
# basemodule.nim
import objmodule
export objmodule.MyObject

proc `$`*(x: MyObject): string = "my object"
# main.nim
import basemodule

var x: MyObject
echo $x

include

includeは他のファイルをそのまま取り込む文です。Cのプリプロセッサでいう#include <***.h>ですね。

include fileA, fileB, fileC

使いどころとしては複数のAPIのwrapperを作るとき、コンパイル時に使用するAPIを切り替えできるようにする際にwhenと組み合わせて使ったりします。

const audioAPI = "wasapi"
when audioAPI == "WASAPI":
  include wasapi.nim
elif audioAPI == "OpenAL":
  include openal.nim
elif audioAPI == "CoreAudio":
  include coreaudio.nim
else:
  raise newException(Exception, "Unknown Audio API")

nimble

nimbleはNimのパッケージマネージャ兼ビルドシステムです。
C/C++と違い、公式で用意されているものなのでほとんどのNimライブラリがコマンド一発で入るというとても便利なものになっています。

$ nimble install csv

上記のコマンドでcsvパーサが一発で入ります。
後は、

import csv

を書いて直ぐに使い始めることができます。

nimbleで入れられるライブラリとして特徴的なのはcompilerライブラリです。 compilerライブラリは文字通りコンパイラのライブラリで、これはNimのコンパイラのライブラリになっています。
NimはコンパイラがNim自身で書かれているので(セルフホスティング)、こうしてコンパイラ自身をライブラリとして使えるようになっています。

まとめ

Nimのモジュールシステムは非常に優れており、これだけでC/C++に比べてアドバンテージがあるのではないでしょうか。
特にcompilerライブラリは他の言語ではなかなか無いライブラリで、とても興味深いのでいずれ単体で記事にしたいところです。

おまけ

NimではC/C++のようにコンパイル時にコンパイラに必要なファイル全てを渡す必要はなく、一つのファイルを渡せば後はimportから自動的に解析してコンパイルしてくれます。
さらにNimではインクリメンタルコンパイルができ、一度コンパイルしてしまえばあとは更新があった部分のみを再コンパイルしてくれるので2回目以降のコンパイルは非常に高速です。
1回目のコンパイルは標準ライブラリを含めてコンパイルされるので時間がかかりますが、2回目以降は高速化されるので実用上問題になることは少ないでしょう。
Nimではロードマップでインクリメンタルコンパイルの大幅な改善も予定されているのでさらに高速になることが予想されるので期待ですね!