1

Nimです、こんばんは
14:00～15:10 セッションs5b

2

自己紹介

浅田睦葉
・ 筑波大学情報学群情報科学類 1年
・ 『プログラミングNim』（インプレスR&D, 2021）著者
・ mock-up 開発
・ Twitter: @momeemt

3

自己紹介
・Nimが好きで3年半くらい書いています

4

自己紹介
・Nimが好きで3年半くらい書いています・メタプログラミングやNimコンパイラに興味があります

5

自己紹介
・Nimが好きで3年半くらい書いています・メタプログラミングやNimコンパイラに興味があります
・組込みプログラミングは初学者なのでお手柔らかにお願いいたします

6

自己紹介
・Nimが好きで3年半くらい書いています・メタプログラミングやNimコンパイラに興味があります
・組込みプログラミングは初学者なのでお手柔らかにお願いいたします▲ 表紙がえらいかわいい2021▲ 表紙がえらいかわいい2022

7

Nimとは？
・Andreas Rumpf 氏が2008年から開発を続けているシステムプログラミング言語

8

Nimとは？
・Andreas Rumpf 氏が2008年から開発を続けているシステムプログラミング言語
・複数の言語をバックエンド言語に持つ静的型付けのコンパイラ言語

9

Nimとは？
・Andreas Rumpf 氏が2008年から開発を続けているシステムプログラミング言語
・複数の言語をバックエンド言語に持つ静的型付けのコンパイラ言語▲ FizzBuzz

10

Nimとは？
・Andreas Rumpf 氏が2008年から開発を続けているシステムプログラミング言語
・複数の言語をバックエンド言語に持つ静的型付けのコンパイラ言語▲ FizzBuzz▲ 構造体とその参照

11

Nimで出来ること
1. Web開発
・JavaScriptとの相性が良く、Webバックエンドフレームワークの開発も盛ん▲ Webフロントエンドフレームワーク▲ Webバックエンドフレームワーク

12

Nimで出来ること
1. Web開発
・日本人作者のWebバックエンドフレームワーク Basolato

・高性能な非同期HTTPサーバー
・非同期クエリビルダ allographer
・開発支援 CLIツール... etc▲ フルスタックフレームワーク

13

Nimで出来ること
2. CLIツール
・メタプログラミングを活かしたオプション解析ライブラリ cligen が非常に優秀▲ オプション解析ライブラリ

14

Nimで出来ること
2. CLIツール
・オプション解析ライブラリ cligen が非常に優秀▲ オプション解析ライブラリ

プロシージャを渡すだけで◎15

Nimで出来ること
2. CLIツール
・オプション解析ライブラリ cligen が非常に優秀▲ オプション解析ライブラリ

プロシージャを渡すだけで◎メタプログラミングによる恩恵

16

Nimで出来ること
3. DevOps
・NimのサブセットであるNimScriptがNimVM上で動作する
・クロスプラットフォームで動作
・Nimでサポートされる強力なメタプログラミングをそのまま扱える・taskが便利

17

Nimで出来ること
3. DevOps
・NimのサブセットであるNimScriptがNimVM上で動作する
・クロスプラットフォームで動作
・Nimでサポートされる強力なメタプログラミングをそのまま扱える・taskが便利▲ こちらの記事がおすすめ18

Nimで出来ること
4. OS開発
・生ポインタ操作が可能でスタンドアロンなバイナリを生成できるのでOSを開発できる

19

Nimで出来ること
4. OS開発
・生ポインタ操作が可能でスタンドアロンなバイナリを生成できるのでOSを開発できる・Nimで開発された実験的なカーネル（2013-）
・https://github.com/dom96/nimkernel

20

Nimで出来ること
4. OS開発
・生ポインタ操作が可能でスタンドアロンなバイナリを生成できるのでOSを開発できる・Nimで開発された実験的なカーネル（2013-）
・https://github.com/dom96/nimkernel・NimでOS開発したいねという話 by sksatさん（2017）
・main関数をブートローダーから呼び出してQEMUで動作させた

21

Nimで出来ること
4. OS開発
・生ポインタ操作が可能でスタンドアロンなバイナリを生成できるのでOSを開発できる・Nimで開発された実験的なカーネル（2013-）
・https://github.com/dom96/nimkernel・NimでOS開発したいねという話 by sksatさん（2017）
・main関数をブートローダーから呼び出してQEMUで動作させた
・Nimによるmikanosの移植 by Double-oxygeNさん (2021)
・Nimによるmikanosの移植 by momeemt（2021）
・@uchan_nos さんが開発した教育用OS mikanosをFFIで呼び出して叩いてインクリメンタルに置き換え▲ 動作したがNim onlyではない22

Nimで出来ること
5. 組込み開発・スタンドアロンなバイナリが生成できるので理屈ではNimでも組込みプログラミングができる
・C/C++とのFFIが洗練されており導入は他言語に比べればしやすい◀︎@EmbeddedNim
・Raspberry PiのNimラッパーやドライバなど組込み関連のライブラリを多く管理している・https://github.com/EmbeddedNim

23

Nimで出来ること
5. 組込み開発・スタンドアロンなバイナリが生成できるので理屈ではNimでも組込みプログラミングができる
・C/C++とのFFIが洗練されており導入は他言語に比べればしやすい◀︎@EmbeddedNim
・Raspberry PiのNimラッパーやドライバなど組込み関連のライブラリを多く管理している・https://github.com/EmbeddedNim

・ArduinoにNimを導入する実験は何人かの先人により行われている
・Nim言語:AVR:Arduino Uno/Nano用にコンパイルしたときのメモ 2019/01
・http://mpu.seesaa.net/article/463862262.html
・Nim on Arduino
・https://disconnected.systems/blog/nim-on-adruino/

24

Nimで出来ること
5. 組込み開発・スタンドアロンなバイナリが生成できるので理屈ではNimでも組込みプログラミングができる
・C/C++とのFFIが洗練されており導入は他言語に比べればしやすい◀︎@EmbeddedNim
・Raspberry PiのNimラッパーやドライバなど組込み関連のライブラリを多く管理している・https://github.com/EmbeddedNim

・ArduinoにNimを導入する実験は何人かの先人により行われている
・Nim言語:AVR:Arduino Uno/Nano用にコンパイルしたときのメモ 2019/01
・http://mpu.seesaa.net/article/463862262.html
・Nim on Arduino
・https://disconnected.systems/blog/nim-on-adruino/
・C99が出力される + Rustほど高い学習コストを要しないので良いと考える意見もある

25

基本文法

▲ FizzBuzzで記述したプログラムを中心に説明します

26

基本文法
Nimを書けるようになりましょう！

プロシージャ（procedure）
・他言語における関数/メソッド/手続き が プロシージャ

27

基本文法
Nimを書けるようになりましょう！

プロシージャ（procedure）
・他言語における関数/メソッド/手続き が プロシージャ
・result変数 が特徴的
・return文と異なり関数の実行を終了しない
・たとえば動的配列を返す場合に便利

28

基本文法
Nimを書けるようになりましょう！

プロシージャ（procedure）
・他言語における関数/メソッド/手続き が プロシージャ
・result変数 が特徴的
・return文と異なり関数の実行を終了しない
・たとえば動的配列を返す場合に便利

一時変数を用意しなくても、
result変数に直接戻り値を構成できる

29

基本文法
Nimを書けるようになりましょう！
UFCS（統一関数呼び出し構文）
・元々はD言語が持つ糖衣構文
・Nimはクラスが無く関数呼び出し構文とメソッド呼び出し構文を同一視できる

30

基本文法
Nimを書けるようになりましょう！

seq[T]とは動的配列型で、実行時に配列サイズを変更可能要素が増えるたびにポインタを確保している

Tは 型引数 で任意の型を入れることができる
seq[T]型は ジェネリクス と呼ばれる抽象型

31

基本文法
Nimを書けるようになりましょう！

seq[T]型とはarray[I; T]型とは動的配列型: 実行時に配列サイズを変更可能要素が増えるたびにポインタを確保している

静的配列型: コンパイル時に配列サイズが確定

Tは 型引数 で任意の型を入れることができる
seq[T]型は ジェネリクス と呼ばれる抽象型

Tは 型引数 で任意の型を入れることができる
Iも 型引数 で整数のコンパイル時定数が入る

32

基本文法
Nimを書けるようになりましょう！

if文 / if式
・Nimにおいて最も基礎的な条件分岐構文

33

基本文法
Nimを書けるようになりましょう！

if文 / if式
・Nimにおいて最も基礎的な条件分岐構文
・厳格に bool値 のみを受け取る

34

基本文法
Nimを書けるようになりましょう！

if文 / if式
・Nimにおいて最も基礎的な条件分岐構文
・厳格に bool値 のみを受け取る▲ if 文▲ if 式

式の場合は必ず値を返す必要がある

35

基本文法
Nimを書けるようになりましょう！

when文 / when式
・コンパイル時における条件分岐構文
・条件に満たすブロックのみコンパイルする
・式の場合は必ず値を返す必要がある▲ when文▲ when式

36

基本文法
Nimを書けるようになりましょう！

for文とは・Nimにおいて最も基礎的なループ文
・イテレータから値を取り出して識別子に代入し、プログラムを実行する
・イテレータから値を取り出し終えると終了する

37

基本文法
Nimを書けるようになりましょう！

イテレータとは・ある集合構造を繰り返し、値を取り出すことができるインターフェース
・イテレータは第一級オブジェクト

38

モジュールとパッケージ
洗練されたモジュールシステムとパッケージディレクトリ

・モジュールシステムによりプログラムを機能によって分割できる・情報の隠蔽やファイルを個別にコンパイル可能にする39

モジュールとパッケージ
洗練されたモジュールシステムとパッケージディレクトリ

・モジュールシステムによりプログラムを機能によって分割できる・情報の隠蔽やファイルを個別にコンパイル可能にする・アスタリスク（*）でマークすることで他のモジュールに公開
・そうでないシンボルは非公開になる

40

モジュールとパッケージ
洗練されたモジュールシステムとパッケージディレクトリ

・except節によって特定のシンボルを除く
・from節によって特定のシンボルのみをインポートする
・from節によって nil をインポートすると接頭辞を強制することができる
・MyModule.symbol3

41

モジュールとパッケージ
洗練されたモジュールシステムとパッケージディレクトリ

ング
ジーケ
パッ

Nimble (ビルドツール兼パッケージマネージャー)
Nimble Package Directory

Nimで書かれたモジュール

42

モジュールとパッケージ
洗練されたモジュールシステムとパッケージディレクトリ

ング
ジーケ
パッ

Nimble (ビルドツール兼パッケージマネージャー)
Nimble Package Directory

Nimで書かれたモジュール

パッケージのインストール

43

モジュールとパッケージ
Nimbleファイル

・パッケージのメタデータ、依存するパッケージとそのバージョン、タスクなどを記述する
・NimScriptが記述できる

44

モジュールとパッケージビルドとパッケージ公開

・Nimbleファイルが存在し、それにより規定されるディレクトリ構造を取るNimモジュールの集合をパッケージと呼んでいる
・Nimbleパッケージはnimbleコマンドによってビルド/実行できる45

モジュールとパッケージビルドとパッケージ公開

・Nimbleファイルが存在し、それにより規定されるディレクトリ構造を取るNimモジュールの集合をパッケージと呼んでいる
・Nimbleパッケージはnimbleコマンドによってビルド/実行できる・開発したバイナリ/ライブラリは次のコマンドにより開始される対話により公開できる

46

Nimの型
整数型 / 浮動小数点数型

符号付き整数

符号なし整数

浮動小数点数

int型

uint型

float型

int8型

uint8型

float32型

int16型

uint16型

float64型

int32型

uint32型

int64型

uint64型

47

Nimの型
真偽値 (bool型)

関係演算子

論理演算子<, <=and>, >=or==, !=

xor
not

48

Nimの型
文字型

・シングルクォーテーションに囲まれたリテラルは char型 に型付けされる・実体は8bitのunsignedな型
・Unicode文字を扱うことはできない

49

Nimの型
文字列型

・ダブルクォーテーションで囲まれたリテラルが string型 に型付けされる
・3つのダブルクォーテーションで囲まれた改行を含む文字列として扱われる
・string型はミュータブルなので文字を追加したり書き換えられる・seq[char]と同じように扱える

50

Nimの型
列挙型

・指定した値から構成される新しい型を定義できる
・内部的にそれぞれの値が整数値として管理される
・orangeは0、muscatは3、strawberryは5であると解釈される・デフォルトでは整数型のように順序を持つ・ユーザーが値に対して独自の値を割り当てることができる

51

Nimの型
部分範囲型

・序数を持つ型の範囲を定めて新しく型を定義できる
・subrange型と呼ばれる・範囲外の値にはコンパイル時に検出可能であればコンパイルエラーを、そうでなければ実行時エラーを投げる

52

Nimの型
構造体型

・構造化型は同時に複数の値を保持することができ、無制限にネストすることができる
・T(fieldA: valueA, fieldB: valueB, ...) という構文で構築できる
・暗黙にプロシージャが定義されるわけではない

53

構造体の性質ディープコピー

momeemt_copyにはmomeemtがディープコピーされる

54

構造体の性質シャローコピー

ディープコピー

momeemt_copyとmomeemtの実体は同じ

momeemt_copyにはmomeemtがディープコピーされる

55

構造体の性質シャローコピー

ディープコピー

momeemt_copyとmomeemtの実体は同じ

生ポインタ

momeemt_copyにはmomeemtがディープコピーされる

ptr[T]型はGCの対象から外れ、自力でメモリ管理する

56

プラグマ
コンパイラに補足情報や実行命令を与える
プラグマを利用することでメタプログラミングにおける特殊な命令を実行できる
また、出力されるCプログラムに対して干渉できるプラグマの呼び出し

57

プラグマ
noSideEffectプラグマ

付与したプロシージャやイテレータが副作用を持たないことをコンパイル時に検査する

58

プラグマ
noSideEffectプラグマ

付与したプロシージャやイテレータが副作用を持たないことをコンパイル時に検査する

funcはnoSideEffectプラグマが付与されたプロシージャの糖衣構文

59

FFI
CのコードをNimで実行する

ソースコードファイル / 共有ヘッダからシンボルを読み込める

headerプラグマに対象となるファイルの(絶対|相対)パスを渡す

60

FFI
CのコードをNimで実行する

標準ライブラリから直接読み込むこともできる

61

FFI
NimのコードをCで実行する

Nimプログラムからmain関数・リンクなしでヘッダーファイルを生成する

62

FFI
NimのコードをCで実行する

Nimプログラムからmain関数・リンクなしでヘッダーファイルを生成する

Nimコンパイラと関連づけてコンパイルを行う

63

ARC / ORC
ARC: Nimにおける決定論的な参照カウンタ

3行目でsomeNumbersがreallocされるので、otherがダングリングポインタにならないようにする

64

ARC / ORC
ARC: Nimにおける決定論的な参照カウンタ

3行目でsomeNumbersがreallocされるので、otherがダングリングポインタにならないようにする
Nimは通常、ディープコピーすることでダングリングポインタを回避→ 右辺値をmoveすることで someNumbers からの参照を無効にする

65

ARC / ORC
ARC: Nimにおける決定論的な参照カウンタ

3行目でsomeNumbersがreallocされるので、otherがダングリングポインタにならないようにする
Nimは通常、ディープコピーすることでダングリングポインタを回避→ 右辺値をmoveすることで someNumbers からの参照を無効にする→ これはC+11における move semantics と同等

66

ARC / ORC
ARC: Nimにおける決定論的な参照カウンタ

3行目でsomeNumbersがreallocされるので、otherがダングリングポインタにならないようにする
Nimは通常、ディープコピーすることでダングリングポインタを回避→ 右辺値をmoveすることで someNumbers からの参照を無効にする→ これはC+11における move semantics と同等
Rustは所有権によりsomeNumbersを無効にしてアクセスするとコンパイルエラーを発生させる→ Nimは参照のみ無効にすることを選んだ。3行目のアクセスは有効で someNumbers == @[3] となる

67

ARC / ORC
ARC: Nimにおける決定論的な参照カウンタ
Nimは明示的なmoveを嫌ったので、ARCは次の条件下において暗黙にmoveする68

ARC / ORC
ARC: Nimにおける決定論的な参照カウンタ
Nimは明示的なmoveを嫌ったので、ARCは次のような状況で暗黙にmoveする

・fn() の結果を参照するのは value のみなので、value に直接 move される69

ARC / ORC
ARC: Nimにおける決定論的な参照カウンタ
Nimは明示的なmoveを嫌ったので、ARCは次のような状況で暗黙にmoveする

・fn() の結果を参照するのは value のみなので、value に直接 move される

・value1がfn2プロシージャの呼び出し以外に使われていないとき、fn1() を fn2 に move して fn2 の戻り値を value2 に move することができる70

ARC / ORC
ARC: Nimにおける決定論的な参照カウンタ
ARCはスコープベースのメモリ管理を行う
値が不要になる時をコンパイル時に解析して、デストラクタを自動的に挿入する71

ARC / ORC
ORC: ARCベースの循環参照コレクタ（非決定論的）
ARCは参照カウンタなので循環参照を処理できない
ORCはARCベースの循環参照コレクタで将来的にはGCをこちらに切り替えることを目指している・ORCはスコープベースのローカルな参照の追跡を行うことができる

72

ジェネリクス
型引数を使って抽象的なシンボルを定義する
・任意の数値型でインスタンスかできる行列型を定義する

73

ジェネリクス
型引数を使って抽象的なシンボルを定義する
・任意の数値型でインスタンスかできる行列型を定義する

・Tに任意の型が入るので欠陥がある

74

ジェネリクス型クラスの導入

・SomeNumberは整数型、浮動小数点数型の型クラス
・TにSomeNumber以外の値が渡ると呼び出し元でエラーを検出する

75

ジェネリクスstatic[T]型によってコンパイル時定数に依存する型を作る

76

テンプレート
衛生的な仕組みを兼ね備える抽象構文木の置換メカニズム

条件式がfalseを返す場合にブロック内が実行される条件分岐

77

テンプレート
衛生的な仕組みを兼ね備える抽象構文木の置換メカニズム

すべての型は==演算子を実装するだけで良い

78

テンプレートインラインプラグマとの違い

テンプレート:
意味解析時に展開される
インラインプラグマ: インライン関数指定（__inline）をして出力するがインライン化するかどうかはバックエンド言語に委ねられる

79

テンプレートインラインプラグマとの違い（テンプレートの場合）
・NimプログラムのエントリポイントであるNimMain内に展開される

80

テンプレートインラインプラグマとの違い（インラインプラグマの場合）
・N_INLINEが付与されてコンパイルされている

81

テンプレートuntyped型とtyped型
・untyped型は遅延評価が行われる

82

テンプレートuntyped型とtyped型
・untyped型は遅延評価が行われる

・ただし、構文上不正なプログラムは抽象構文木に変換できない83

テンプレートuntyped型とtyped型
・typed型は呼び出し時に意味解析が行われる

84

テンプレートテンプレートが持つ衛生性
・テンプレートはグローバルに公開されるプログラムとスコープを持つプログラムを分けて生成する

85

テンプレート
衛生性を管理する・injectプラグマによりグローバルに公開でき、gensymプラグマによりスコープに閉じ込められる

86

マクロ
抽象構⽂⽊を受け取り、抽象構⽂⽊を返す⾔語機能▲ プロシージャで実装したデバッグユーティリティ

87

マクロ
抽象構⽂⽊を受け取り、抽象構⽂⽊を返す⾔語機能▲ マクロで実装したデバッグユーティリティ

88

マクロ
マクロを展開するマクロで構造を見破る▲ expandMacrosマクロを使う

89

マクロ
マクロを展開するマクロで構造を見破る▲ 生成されるプログラム (デバッグ出力)

90

マクロ
コンパイル時関数実⾏ (CTFE) をサポート
・一部制限があるが、プロシージャ、イテレータ、テンプレート、マクロをコンパイル時に実行できる！

91

マクロ受け取る抽象構文木に対して制限をかける
・コンパイル時にユーザーカスタムな意味解析エラー（コンパイルエラー）を出力できる▲ 受け取る引数は全て識別子（nnkIdent）でなければならない

92

マクロ
受け取る抽象構文木に対して制限をかける
・コンパイル時にユーザーカスタムな意味解析エラー（コンパイルエラー）を出力できる▲ 受け取る引数は1つ以上でなければならない

93

マクロ
quoteプロシージャを使ったより直感的なマクロ構築▲ 生成されるプログラムをプログラムとして記述できる

94

マクロに関連するプラグマ
compileTime プラグマ

▲ NimNodeを受け取る/返すプロシージャは暗黙にcompileTimeプラグマを持つ

95

マクロに関連するプラグマ
error プラグマ

▲ シンボルを呼び出すとコンパイルエラーが発生する

96

ユーザー定義プラグマ
・テンプレート/マクロはプラグマとして利用できる

97

ユーザー定義プラグマ
・テンプレート/マクロはプラグマとして利用できる▲プラグマとして呼び出されたマクロは上のように展開される

98

項書き換えマクロコンパイル時最適化を目的にパターンマッチに基づいて抽象構文木を置換する機能
最適化を定義してコンパイルパイプラインを拡張するインターフェース▲ 単位行列との行列積は計算を省略する最適化
引数制約式におけるパターンマッチ演算子
・ `|`演算子 ... 順序付きの選択肢の作成
・`{}`演算子 ... 式を引数にバインドする・`~`演算子 ... パターンの否定・`*`演算子 ... 式を平坦化する・`**`演算子 ... 式を逆ポーランド記法の順序で収集する

99

項書き換えマクロ`|`演算子 順序付きの選択肢を作成する

100

項書き換えマクロ`{}`演算子 式を引数にバインドする

101

項書き換えマクロ`~`演算子 パターンの否定102

項書き換えマクロ`*`演算子 式をフラットにする

103

項書き換えマクロ`**`演算子 式を逆ポーランド記法の順序で収集する

抽象構文木からユーザー最適化を注入できる

104

caseマクロ・case文を任意の具体型に対して拡張できる実験的機能
・{.experimental: "caseStmtMacros".}

105

caseマクロ・case文を任意の具体型に対して拡張できる実験的機能
・{.experimental: "caseStmtMacros".}
・ユーザー定義パターンマッチを実装できる・左は Option[T] 型に対して機能する▲ Rustライクなパターンマッチ

106

forループマクロ

・イテレータにForLoopStmt型を受け取るマクロを置くことでfor文全体を書き換える機能

107

forループマクロ

・イテレータにForLoopStmt型を受け取るマクロを置くことでfor文全体を書き換える機能
・左は多重ループに展開するマクロを実装している▲ 3重ループに展開される

108

まとめ
・NimはC/C++/Objective-C/JavaScriptをバックエンド言語に持つコンパイル言語です
・静的型付け言語であり、ガベージコレクタ（GC）を持ちます
・Web開発・CLI開発・デスクトップアプリ開発・OS開発・組込み開発など幅広く適用できます
・Nimはビルドツール兼パッケージマネージャーであるNimbleを使って開発を行います
・数値型や文字列型はもちろん、列挙型、構造体型、メタ型、コンパイル時定数型、ジェネリクスなど十分な型の表現力を持ちます
・洗練されたFFIにより、非常に簡単にCやC++、JavaScript、Objective-Cと相互運用できます・テンプレートは衛生性を持った抽象構文木の置換機能です
・マクロは抽象構文木を受け取り、新たな抽象構文木を返却する言語機能です
・現在Nimには新しいGCの導入が進んでおり、決定論的な参照カウンタであるARCとそれをベースにした循環参照コレクタであるORCが検討されています。
・項書き換えマクロにより、ユーザー定義最適化を記述してコンパイルパイプラインを拡張できます・caseマクロにより、型に対するユーザー定義パターンマッチを記述できます

109

参考文献
・Nim Manual・https://nim-lang.org/docs/manual.html
・Nim Experimental Features
・https://nim-lang.org/docs/manual_experimental.html
・Nim Compiler User Guide
・https://nim-lang.org/docs/nimc.html
・std/macros
・https://nim-lang.org/docs/macros.html
・Introduction to ARC/ORC in Nim
・https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc-in-nim.html
・Move semantics for Nim・https://youtu.be/yA32Wxl59wo