Skip to content

Latest commit

 

History

History
132 lines (89 loc) · 4.14 KB

2019-06-30-dev-rc.mkd

File metadata and controls

132 lines (89 loc) · 4.14 KB

GC付き言語 "RC" を作っている

ある日,何気なくTwitterを眺めていると,

「GCのことが知りたい」

突然そう思った.

参照カウント式のGCを実装する

GCで,最も基本的な方式の一つに,参照カウントがある. 元々名前と原理を大まかには知っていたので,とりあえず実装してみることにした.

こうして出来たのがrefcount.c である.

簡単な実装ではあるけれど,これはこうやって使う.

#include "./refcount.h"

int main(int argc, const char *argv[])
{
  Person* p1 = new_person("musou1500", 24);
  Ref ref1 = new_ref(p1, person_destruct);

  Person* p2 = new_person("musou1501", 24);
  Ref ref2 = new_ref(p2, person_destruct);
  
  printf("ref2 = ref1;\n");
  ref_assign(&ref2, &ref1);
  // ここで `p2` が開放される
  
  printf("ref1 = NULL;\n");
  ref_assign(&ref1, NULL);

  printf("ref2 = NULL;\n");
  ref_assign(&ref1, NULL);
  // ここで `p1` が開放される

  return 0;
}

感動した.簡単ながら,ちゃんと動いている. ちゃんと動いて入るのだが,これを実際に使うことを考えるとなかなか面倒くさいと思う.

GCしたければ Ref オブジェクトを通す必要があるし, 忘れずに逐一 ref_assign を呼び出す必要がある.

人間にそんなことができるのか.

自作言語を作ろう

そうなると,独自の言語を実装してみよう,となるのは自然な発想だと言える. 「GC付きのC言語」のような,簡単な言語を実装し,遊んでみようというわけだ.

ヒープにメモリ領域を確保し,Ref のようなオブジェクトに引き渡すような構文があれば, 言語の使用者はその内部実装を意識することなく,GCを利用できるはずだ.

そこで,以下のような alloc 構文を考えた.

// ヒープにメモリ領域を確保し,初期化する
var p1 = alloc Person {
  .name = "musou1500",
  .age = 15
};

var p2 = alloc Person {
  .name = "musou1501",
  .age = 15
};

// p2の参照先 "musou1501" が開放される
p2 = p1;

// "musou1500" が開放される
p1 = null;
p2 = null;

// 配列をヒープに確保する
var str = alloc char[7];

細かいことは後で考えるとして,とりあえずこれで良さそうだ.

そういうわけで,この言語のコンパイラを開発し始めた. 僕はこの言語を "Reference Count" にちなんで,「RC」と呼ぶことにした.

レポジトリはここにある. musou1500/learn_gc

今はひたすらパーサとトークナイザを書いている段階で, 型チェックとコード生成器はまだ着手できてない.

今後の予定

パイプライン演算子

HaskellやElmなんかでも導入されている,パイプライン演算子があると良さそうだ. 例えば,以下のように使える.

return readline()
  |> s_ucfirst(_),
  |> s_concat("Hello", _)
  |> println(_)

s_ucfirsts_concat は以下のように振る舞う.

  • s_ucfirst 渡された文字列の最初の文字を大文字にしたものを返す.
  • s_concat 2つの文字列を連結して返す
// "Apple"
s_ucfirst("apple");

// "Hello, World"
s_concat("Hello, ", "World");

これらの関数は,新しくヒープにメモリ領域を確保して返す. しかし,RCにはGCが付いているので,引数に渡した文字列をどうしようとか,新しく確保されたメモリ領域はいつ開放すれば良いだろうとか,そういうことを考える必要はない.

GC以外でのメモリ管理

例えば,RustやC++ではRAIIっぽいメモリ管理をサポートしていて,GC無しでのメモリ管理が可能になっている.

今後,そういった機能を取り入れられるようにしたい. ただ,現状知識もなく,そういうことを想定した言語設計をしているわけでもないのでできるかどうかわからない.